From 69da11a263f99104dc3e3e01abe0bcc792e3b1ca Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Mon, 20 Jan 2020 09:07:46 +0100 Subject: [PATCH] cmd/syncthing: Always use monitor process (fixes #4774, fixes #5786) (#6278) --- cmd/syncthing/main.go | 15 ++----- cmd/syncthing/monitor.go | 49 +++++++++++++++-------- etc/linux-desktop/syncthing-start.desktop | 2 +- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 37872fcf2..4fd37807f 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -47,6 +47,7 @@ import ( const ( tlsDefaultCommonName = "syncthing" deviceCertLifetimeDays = 20 * 365 + sigTerm = syscall.Signal(15) ) const ( @@ -225,7 +226,7 @@ func parseCommandLineOptions() RuntimeOptions { flag.BoolVar(&options.Verbose, "verbose", false, "Print verbose log output") flag.BoolVar(&options.paused, "paused", false, "Start with all devices and folders paused") flag.BoolVar(&options.unpaused, "unpaused", false, "Start with all devices and folders unpaused") - flag.StringVar(&options.logFile, "logfile", options.logFile, "Log file name (still always logs to stdout). Cannot be used together with -no-restart/STNORESTART environment variable.") + flag.StringVar(&options.logFile, "logfile", options.logFile, "Log file name (still always logs to stdout).") flag.IntVar(&options.logMaxSize, "log-max-size", options.logMaxSize, "Maximum size of any file (zero to disable log rotation).") flag.IntVar(&options.logMaxFiles, "log-max-old-files", options.logMaxFiles, "Number of old files to keep (zero to keep only current).") flag.StringVar(&options.auditFile, "auditfile", options.auditFile, "Specify audit file (use \"-\" for stdout, \"--\" for stderr)") @@ -260,15 +261,6 @@ func main() { os.Setenv("STGUIAPIKEY", options.guiAPIKey) } - // Check for options which are not compatible with each other. We have - // to check logfile before it's set to the default below - we only want - // to complain if they set -logfile explicitly, not if it's set to its - // default location - if options.noRestart && (options.logFile != "" && options.logFile != "-") { - l.Warnln("-logfile may not be used with -no-restart or STNORESTART") - os.Exit(syncthing.ExitError.AsInt()) - } - if options.hideConsole { osutil.HideConsole() } @@ -381,7 +373,7 @@ func main() { return } - if innerProcess || options.noRestart { + if innerProcess { syncthingMain(options) } else { monitorMain(options) @@ -677,7 +669,6 @@ func setupSignalHandling(app *syncthing.App) { // Exit with "success" code (no restart) on INT/TERM stopSign := make(chan os.Signal, 1) - sigTerm := syscall.Signal(15) signal.Notify(stopSign, os.Interrupt, sigTerm) go func() { <-stopSign diff --git a/cmd/syncthing/monitor.go b/cmd/syncthing/monitor.go index 72986e8d0..f8ed38baf 100644 --- a/cmd/syncthing/monitor.go +++ b/cmd/syncthing/monitor.go @@ -21,6 +21,7 @@ import ( "time" "github.com/syncthing/syncthing/lib/events" + "github.com/syncthing/syncthing/lib/fs" "github.com/syncthing/syncthing/lib/locations" "github.com/syncthing/syncthing/lib/osutil" "github.com/syncthing/syncthing/lib/protocol" @@ -50,6 +51,9 @@ func monitorMain(runtimeOptions RuntimeOptions) { logFile := runtimeOptions.logFile if logFile != "-" { + if expanded, err := fs.ExpandTilde(logFile); err == nil { + logFile = expanded + } var fileDst io.Writer if runtimeOptions.logMaxSize > 0 { open := func(name string) (io.WriteCloser, error) { @@ -79,7 +83,6 @@ func monitorMain(runtimeOptions RuntimeOptions) { var restarts [countRestarts]time.Time stopSign := make(chan os.Signal, 1) - sigTerm := syscall.Signal(15) signal.Notify(stopSign, os.Interrupt, sigTerm) restartSign := make(chan os.Signal, 1) sigHup := syscall.Signal(1) @@ -111,7 +114,7 @@ func monitorMain(runtimeOptions RuntimeOptions) { panic(err) } - l.Infoln("Starting syncthing") + l.Debugln("Starting syncthing") err = cmd.Start() if err != nil { l.Warnln("Error starting the main Syncthing process:", err) @@ -144,12 +147,13 @@ func monitorMain(runtimeOptions RuntimeOptions) { exit <- cmd.Wait() }() + stopped := false select { case s := <-stopSign: l.Infof("Signal %d received; exiting", s) cmd.Process.Signal(sigTerm) - <-exit - return + err = <-exit + stopped = true case s := <-restartSign: l.Infof("Signal %d received; restarting", s) @@ -157,20 +161,31 @@ func monitorMain(runtimeOptions RuntimeOptions) { err = <-exit case err = <-exit: - if err == nil { - // Successful exit indicates an intentional shutdown - return - } else if exiterr, ok := err.(*exec.ExitError); ok { - if exiterr.ExitCode() == syncthing.ExitUpgrade.AsInt() { - // 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 { - l.Warnln("Restart:", err) - } - return - } + } + + if err == nil { + // Successful exit indicates an intentional shutdown + os.Exit(syncthing.ExitSuccess.AsInt()) + } + + if exiterr, ok := err.(*exec.ExitError); ok { + exitCode := exiterr.ExitCode() + if stopped || runtimeOptions.noRestart { + os.Exit(exitCode) } + if exitCode == syncthing.ExitUpgrade.AsInt() { + // 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 { + l.Warnln("Restart:", err) + } + os.Exit(exitCode) + } + } + + if runtimeOptions.noRestart { + os.Exit(syncthing.ExitError.AsInt()) } l.Infoln("Syncthing exited:", err) diff --git a/etc/linux-desktop/syncthing-start.desktop b/etc/linux-desktop/syncthing-start.desktop index f46a9d3c7..b84f6dce9 100644 --- a/etc/linux-desktop/syncthing-start.desktop +++ b/etc/linux-desktop/syncthing-start.desktop @@ -2,7 +2,7 @@ Name=Start Syncthing GenericName=File synchronization Comment=Starts the main syncthing process in the background. -Exec=/usr/bin/syncthing -no-browser +Exec=/usr/bin/syncthing -no-browser -logfile=~/.config/syncthing/syncthing.log Icon=syncthing Terminal=false Type=Application