2014-11-16 21:13:20 +01:00
// Copyright (C) 2014 The Syncthing Authors.
2014-09-29 21:43:32 +02:00
//
2015-03-07 21:36:35 +01:00
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
2017-02-09 07:52:18 +01:00
// You can obtain one at https://mozilla.org/MPL/2.0/.
2014-06-01 22:50:14 +02:00
2013-12-15 11:43:31 +01:00
package main
import (
2015-10-03 17:25:21 +02:00
"bytes"
2013-12-15 11:43:31 +01:00
"crypto/tls"
2014-01-26 14:28:41 +01:00
"flag"
2014-01-08 14:37:33 +01:00
"fmt"
2017-01-03 09:54:28 +01:00
"io"
2015-04-30 21:33:32 +02:00
"io/ioutil"
2013-12-15 11:43:31 +01:00
"log"
"net/http"
2019-02-12 07:58:24 +01:00
_ "net/http/pprof" // Need to import this to support STPROFILER.
2016-05-28 16:08:26 +02:00
"net/url"
2013-12-15 11:43:31 +01:00
"os"
2015-12-14 09:57:49 +01:00
"os/signal"
2016-05-28 16:08:26 +02:00
"path"
2014-03-28 14:36:57 +01:00
"path/filepath"
2014-01-10 00:09:27 +01:00
"runtime"
2014-04-14 12:13:50 +02:00
"runtime/pprof"
2015-10-03 17:25:21 +02:00
"sort"
2014-04-18 13:20:42 +02:00
"strconv"
2015-12-14 09:57:49 +01:00
"syscall"
2013-12-15 11:43:31 +01:00
"time"
2014-04-08 13:45:18 +02:00
2019-02-12 07:58:24 +01:00
"github.com/syncthing/syncthing/lib/build"
2015-08-06 11:29:25 +02:00
"github.com/syncthing/syncthing/lib/config"
2015-10-13 20:52:22 +02:00
"github.com/syncthing/syncthing/lib/dialer"
2015-08-06 11:29:25 +02:00
"github.com/syncthing/syncthing/lib/events"
2017-08-19 16:36:56 +02:00
"github.com/syncthing/syncthing/lib/fs"
2019-02-12 07:58:24 +01:00
"github.com/syncthing/syncthing/lib/locations"
2015-10-03 17:25:21 +02:00
"github.com/syncthing/syncthing/lib/logger"
2015-08-06 11:29:25 +02:00
"github.com/syncthing/syncthing/lib/osutil"
2015-09-22 19:38:46 +02:00
"github.com/syncthing/syncthing/lib/protocol"
2019-07-14 12:43:13 +02:00
"github.com/syncthing/syncthing/lib/syncthing"
2015-09-02 22:05:54 +02:00
"github.com/syncthing/syncthing/lib/tlsutil"
2015-08-06 11:29:25 +02:00
"github.com/syncthing/syncthing/lib/upgrade"
2015-07-17 22:22:07 +02:00
2019-02-14 21:29:14 +01:00
"github.com/pkg/errors"
2014-04-19 16:38:11 +02:00
)
2014-09-02 13:08:24 +02:00
const (
exitSuccess = 0
exitError = 1
exitNoUpgradeAvailable = 2
exitRestarting = 3
2014-09-13 16:25:39 +02:00
exitUpgrading = 4
2014-09-02 13:08:24 +02:00
)
2015-03-26 23:26:51 +01:00
const (
2015-09-02 22:05:54 +02:00
bepProtocolName = "bep/1.0"
tlsDefaultCommonName = "syncthing"
2015-10-03 17:25:21 +02:00
maxSystemErrors = 5
initialSystemLog = 10
maxSystemLog = 250
2015-03-26 23:26:51 +01:00
)
2015-03-05 15:58:16 +01:00
2019-02-14 00:07:27 +01:00
var myID protocol . DeviceID
2014-01-26 14:28:41 +01:00
2014-03-09 08:48:29 +01:00
const (
usage = "syncthing [options]"
2014-10-06 17:55:54 +02:00
extraUsage = `
The - logflags value is a sum of the following :
2014-06-04 10:24:30 +02:00
1 Date
2 Time
4 Microsecond time
8 Long filename
16 Short filename
I . e . to prefix each log line with date and time , set - logflags = 3 ( 1 + 2 from
above ) . The value 0 is used to disable all of the above . The default is to
show time only ( 2 ) .
2014-03-12 10:12:35 +01:00
2014-10-06 17:55:54 +02:00
Development Settings
-- -- -- -- -- -- -- -- -- --
2014-08-27 23:38:36 +02:00
2017-01-10 08:50:11 +01:00
The following environment variables modify Syncthing ' s behavior in ways that
2014-10-06 17:55:54 +02:00
are mostly useful for developers . Use with care .
2014-08-16 00:24:24 +02:00
2016-01-09 02:11:06 +01:00
STNODEFAULTFOLDER Don ' t create a default folder when starting for the first
2017-01-10 08:50:11 +01:00
time . This variable will be ignored anytime after the first
2016-01-09 02:11:06 +01:00
run .
2014-04-14 12:13:50 +02:00
2016-01-09 02:11:06 +01:00
STGUIASSETS Directory to load GUI assets from . Overrides compiled in
assets .
2014-04-14 12:13:50 +02:00
2016-01-09 02:11:06 +01:00
STTRACE A comma separated string of facilities to trace . The valid
facility strings listed below .
2014-08-13 14:38:23 +02:00
2017-01-10 08:50:11 +01:00
STPROFILER Set to a listen address such as "127.0.0.1:9090" to start
the profiler with HTTP access .
2014-08-13 14:38:23 +02:00
2016-01-09 02:11:06 +01:00
STCPUPROFILE Write a CPU profile to cpu - $ pid . pprof on exit .
2014-08-13 14:38:23 +02:00
2016-01-09 02:11:06 +01:00
STHEAPPROFILE Write heap profiles to heap - $ pid - $ timestamp . pprof each time
heap usage increases .
2014-08-13 14:38:23 +02:00
2016-01-09 02:11:06 +01:00
STBLOCKPROFILE Write block profiles to block - $ pid - $ timestamp . pprof every 20
seconds .
2014-11-26 19:48:31 +01:00
2016-01-09 02:11:06 +01:00
STPERFSTATS Write running performance statistics to perf - $ pid . csv . Not
supported on Windows .
2015-01-27 22:21:39 +01:00
2017-01-10 08:50:11 +01:00
STDEADLOCKTIMEOUT Used for debugging internal deadlocks ; sets debug
sensitivity . Use only under direction of a developer .
2017-12-13 20:40:12 +01:00
STLOCKTHRESHOLD Used for debugging internal deadlocks ; sets debug
sensitivity . Use only under direction of a developer .
2017-01-10 08:50:11 +01:00
STNORESTART Equivalent to the - no - restart argument . Disable the
Syncthing monitor process which handles restarts for some
configuration changes , upgrades , crashes and also log file
writing ( stdout is still written ) .
2016-01-09 02:11:06 +01:00
STNOUPGRADE Disable automatic upgrades .
2015-03-29 19:05:22 +02:00
2016-09-23 21:33:54 +02:00
STHASHING Select the SHA256 hashing package to use . Possible values
are "standard" for the Go standard library implementation ,
"minio" for the github . com / minio / sha256 - simd implementation ,
and blank ( the default ) for auto detection .
2018-02-21 08:26:57 +01:00
STRECHECKDBEVERY Set to a time interval to override the default database
2017-12-14 10:51:17 +01:00
check interval of 30 days ( 720 h ) . The interval understands
"h" , "m" and "s" abbreviations for hours minutes and seconds .
Valid values are like "720h" , "30s" , etc .
2016-01-09 02:11:06 +01:00
GOMAXPROCS Set the maximum number of CPU cores to use . Defaults to all
available CPU cores .
GOGC Percentage of heap growth at which to trigger GC . Default is
100. Lower numbers keep peak memory usage down , at the price
2017-01-10 08:50:11 +01:00
of CPU usage ( i . e . performance ) .
2015-10-03 17:25:21 +02:00
Debugging Facilities
-- -- -- -- -- -- -- -- -- --
The following are valid values for the STTRACE variable :
% s `
2014-03-09 08:48:29 +01:00
)
2015-12-17 23:40:46 +01:00
// Environment options
2014-09-02 13:08:24 +02:00
var (
2019-07-14 12:43:13 +02:00
innerProcess = os . Getenv ( "STNORESTART" ) != "" || os . Getenv ( "STMONITORED" ) != ""
noDefaultFolder = os . Getenv ( "STNODEFAULTFOLDER" ) != ""
2015-12-17 23:40:46 +01:00
)
type RuntimeOptions struct {
2019-07-14 12:43:13 +02:00
syncthing . Options
2019-03-12 08:12:08 +01:00
confDir string
resetDatabase bool
showVersion bool
showPaths bool
showDeviceId bool
doUpgrade bool
doUpgradeCheck bool
upgradeTo string
noBrowser bool
browserOnly bool
hideConsole bool
logFile string
auditEnabled bool
auditFile string
paused bool
unpaused bool
guiAddress string
guiAPIKey string
generateDir string
noRestart bool
cpuProfile bool
stRestarting bool
logFlags int
showHelp bool
allowNewerConfig bool
2015-12-17 23:40:46 +01:00
}
2014-09-02 13:08:24 +02:00
2015-12-17 23:40:46 +01:00
func defaultRuntimeOptions ( ) RuntimeOptions {
options := RuntimeOptions {
2019-07-14 12:43:13 +02:00
Options : syncthing . Options {
AssetDir : os . Getenv ( "STGUIASSETS" ) ,
NoUpgrade : os . Getenv ( "STNOUPGRADE" ) != "" ,
ProfilerURL : os . Getenv ( "STPROFILER" ) ,
} ,
2015-12-17 23:40:46 +01:00
noRestart : os . Getenv ( "STNORESTART" ) != "" ,
cpuProfile : os . Getenv ( "STCPUPROFILE" ) != "" ,
stRestarting : os . Getenv ( "STRESTART" ) != "" ,
2015-12-18 17:34:39 +01:00
logFlags : log . Ltime ,
2015-12-17 23:40:46 +01:00
}
2014-12-04 21:25:35 +01:00
2015-12-18 17:34:39 +01:00
if os . Getenv ( "STTRACE" ) != "" {
2017-06-02 09:04:06 +02:00
options . logFlags = logger . DebugFlags
2015-12-18 17:34:39 +01:00
}
2015-12-21 11:55:58 +01:00
if runtime . GOOS != "windows" {
// On non-Windows, we explicitly default to "-" which means stdout. On
// Windows, the blank options.logFile will later be replaced with the
// default path, unless the user has manually specified "-" or
// something else.
options . logFile = "-"
2014-10-19 14:57:03 +02:00
}
2015-12-17 23:40:46 +01:00
return options
}
func parseCommandLineOptions ( ) RuntimeOptions {
options := defaultRuntimeOptions ( )
flag . StringVar ( & options . generateDir , "generate" , "" , "Generate key and config in specified dir, then exit" )
flag . StringVar ( & options . guiAddress , "gui-address" , options . guiAddress , "Override GUI address (e.g. \"http://192.0.2.42:8443\")" )
flag . StringVar ( & options . guiAPIKey , "gui-apikey" , options . guiAPIKey , "Override GUI API key" )
flag . StringVar ( & options . confDir , "home" , "" , "Set configuration directory" )
2015-12-18 17:34:39 +01:00
flag . IntVar ( & options . logFlags , "logflags" , options . logFlags , "Select information in log line prefix (see below)" )
2015-12-17 23:40:46 +01:00
flag . BoolVar ( & options . noBrowser , "no-browser" , false , "Do not start browser" )
flag . BoolVar ( & options . browserOnly , "browser-only" , false , "Open GUI in browser" )
2017-01-10 08:50:11 +01:00
flag . BoolVar ( & options . noRestart , "no-restart" , options . noRestart , "Disable monitor process, managed restarts and log file writing" )
2016-12-26 13:48:54 +01:00
flag . BoolVar ( & options . resetDatabase , "reset-database" , false , "Reset the database, forcing a full rescan and resync" )
2019-07-14 12:43:13 +02:00
flag . BoolVar ( & options . ResetDeltaIdxs , "reset-deltas" , false , "Reset delta index IDs, forcing a full index exchange" )
2015-12-17 23:40:46 +01:00
flag . BoolVar ( & options . doUpgrade , "upgrade" , false , "Perform upgrade" )
flag . BoolVar ( & options . doUpgradeCheck , "upgrade-check" , false , "Check for available upgrade" )
flag . BoolVar ( & options . showVersion , "version" , false , "Show version" )
2018-09-15 08:17:31 +02:00
flag . BoolVar ( & options . showHelp , "help" , false , "Show this help" )
2016-02-02 10:27:01 +01:00
flag . BoolVar ( & options . showPaths , "paths" , false , "Show configuration paths" )
2017-09-25 08:05:21 +02:00
flag . BoolVar ( & options . showDeviceId , "device-id" , false , "Show the device ID" )
2015-12-17 23:40:46 +01:00
flag . StringVar ( & options . upgradeTo , "upgrade-to" , options . upgradeTo , "Force upgrade directly from specified URL" )
flag . BoolVar ( & options . auditEnabled , "audit" , false , "Write events to audit file" )
2019-07-14 12:43:13 +02:00
flag . BoolVar ( & options . Verbose , "verbose" , false , "Print verbose log output" )
2016-12-21 19:41:25 +01:00
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" )
2018-03-12 13:17:12 +01:00
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." )
2017-01-03 09:54:28 +01:00
flag . StringVar ( & options . auditFile , "auditfile" , options . auditFile , "Specify audit file (use \"-\" for stdout, \"--\" for stderr)" )
2019-03-12 08:12:08 +01:00
flag . BoolVar ( & options . allowNewerConfig , "allow-newer-config" , false , "Allow loading newer than current config version" )
2015-12-17 23:40:46 +01:00
if runtime . GOOS == "windows" {
// Allow user to hide the console window
2015-12-18 18:28:02 +01:00
flag . BoolVar ( & options . hideConsole , "no-console" , false , "Hide console window" )
2015-12-17 23:40:46 +01:00
}
2014-10-06 17:55:54 +02:00
2016-02-02 10:27:01 +01:00
longUsage := fmt . Sprintf ( extraUsage , debugFacilities ( ) )
2015-10-03 17:25:21 +02:00
flag . Usage = usageFor ( flag . CommandLine , usage , longUsage )
2014-01-26 14:28:41 +01:00
flag . Parse ( )
2015-12-17 23:40:46 +01:00
2016-11-27 12:21:05 +01:00
if len ( flag . Args ( ) ) > 0 {
flag . Usage ( )
os . Exit ( 2 )
}
2015-12-17 23:40:46 +01:00
return options
2015-12-16 21:33:14 +01:00
}
func main ( ) {
2015-12-17 23:40:46 +01:00
options := parseCommandLineOptions ( )
2015-12-18 17:34:39 +01:00
l . SetFlags ( options . logFlags )
2014-01-08 14:37:33 +01:00
2015-12-17 23:40:46 +01:00
if options . guiAddress != "" {
2015-10-12 15:27:57 +02:00
// The config picks this up from the environment.
2015-12-17 23:40:46 +01:00
os . Setenv ( "STGUIADDRESS" , options . guiAddress )
2015-10-12 15:27:57 +02:00
}
2015-12-17 23:40:46 +01:00
if options . guiAPIKey != "" {
2015-10-12 15:27:57 +02:00
// The config picks this up from the environment.
2015-12-17 23:40:46 +01:00
os . Setenv ( "STGUIAPIKEY" , options . guiAPIKey )
2015-10-12 15:27:57 +02:00
}
2017-01-18 18:59:48 +01:00
// 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 != "-" ) {
2019-02-14 21:29:14 +01:00
l . Warnln ( "-logfile may not be used with -no-restart or STNORESTART" )
os . Exit ( exitError )
2017-01-18 13:19:22 +01:00
}
2015-12-18 18:28:02 +01:00
if options . hideConsole {
2014-12-04 21:25:35 +01:00
osutil . HideConsole ( )
}
2015-12-17 23:40:46 +01:00
if options . confDir != "" {
2014-10-06 17:55:54 +02:00
// Not set as default above because the string can be really long.
2017-03-04 08:49:48 +01:00
if ! filepath . IsAbs ( options . confDir ) {
2017-03-09 15:57:12 +01:00
var err error
options . confDir , err = filepath . Abs ( options . confDir )
2017-03-04 08:49:48 +01:00
if err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Failed to make options path absolute:" , err )
os . Exit ( exitError )
2017-03-04 08:49:48 +01:00
}
}
2019-02-12 07:58:24 +01:00
if err := locations . SetBaseDir ( locations . ConfigBaseDir , options . confDir ) ; err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( err )
os . Exit ( exitError )
2019-02-12 07:58:24 +01:00
}
2015-04-03 20:22:39 +02:00
}
2015-12-21 11:55:58 +01:00
if options . logFile == "" {
// Blank means use the default logfile location. We must set this
// *after* expandLocations above.
2019-02-12 07:58:24 +01:00
options . logFile = locations . Get ( locations . LogFile )
2015-12-21 11:55:58 +01:00
}
2019-07-14 12:43:13 +02:00
if options . AssetDir == "" {
2015-12-26 13:31:58 +01:00
// The asset dir is blank if STGUIASSETS wasn't set, in which case we
// should look for extra assets in the default place.
2019-07-14 12:43:13 +02:00
options . AssetDir = locations . Get ( locations . GUIAssets )
2015-12-26 13:31:58 +01:00
}
2015-12-17 23:40:46 +01:00
if options . showVersion {
2019-02-12 07:58:24 +01:00
fmt . Println ( build . LongVersion )
2014-04-14 12:13:50 +02:00
return
2013-12-15 11:43:31 +01:00
}
2014-01-08 14:37:33 +01:00
2018-09-15 08:17:31 +02:00
if options . showHelp {
flag . Usage ( )
return
}
2016-02-02 10:27:01 +01:00
if options . showPaths {
2018-03-28 19:02:43 +02:00
showPaths ( options )
2016-02-02 10:27:01 +01:00
return
}
2017-09-25 08:05:21 +02:00
if options . showDeviceId {
2019-02-12 07:58:24 +01:00
cert , err := tls . LoadX509KeyPair (
locations . Get ( locations . CertFile ) ,
locations . Get ( locations . KeyFile ) ,
)
2017-09-25 08:05:21 +02:00
if err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Error reading device ID:" , err )
os . Exit ( exitError )
2017-09-25 08:05:21 +02:00
}
myID = protocol . NewDeviceID ( cert . Certificate [ 0 ] )
fmt . Println ( myID )
return
}
2015-12-17 23:40:46 +01:00
if options . browserOnly {
2019-02-14 21:29:14 +01:00
if err := openGUI ( ) ; err != nil {
l . Warnln ( "Failed to open web UI:" , err )
os . Exit ( exitError )
}
2015-12-16 16:11:01 +01:00
return
}
2015-12-17 23:40:46 +01:00
if options . generateDir != "" {
2019-02-14 21:29:14 +01:00
if err := generate ( options . generateDir ) ; err != nil {
l . Warnln ( "Failed to generate config and keys:" , err )
os . Exit ( exitError )
}
2014-08-03 09:41:08 +02:00
return
2014-07-31 21:29:44 +02:00
}
2014-09-18 00:19:23 +02:00
// Ensure that our home directory exists.
2019-02-14 21:29:14 +01:00
if err := ensureDir ( locations . GetBaseDir ( locations . ConfigBaseDir ) , 0700 ) ; err != nil {
l . Warnln ( "Failure on home directory:" , err )
os . Exit ( exitError )
}
2014-09-18 00:19:23 +02:00
2015-12-17 23:40:46 +01:00
if options . upgradeTo != "" {
err := upgrade . ToURL ( options . upgradeTo )
2014-12-22 12:07:04 +01:00
if err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Error while Upgrading:" , err )
os . Exit ( exitError )
2014-12-22 12:07:04 +01:00
}
2016-01-16 23:01:57 +01:00
l . Infoln ( "Upgraded from" , options . upgradeTo )
2014-12-22 12:07:04 +01:00
return
}
2015-12-17 23:40:46 +01:00
if options . doUpgradeCheck {
2015-12-16 20:29:37 +01:00
checkUpgrade ( )
return
}
2014-12-08 16:36:15 +01:00
2015-12-17 23:40:46 +01:00
if options . doUpgrade {
2015-12-16 20:29:37 +01:00
release := checkUpgrade ( )
performUpgrade ( release )
2014-12-08 16:36:15 +01:00
return
2014-07-31 10:26:45 +02:00
}
2016-12-26 13:48:54 +01:00
if options . resetDatabase {
2019-02-02 10:11:42 +01:00
if err := resetDB ( ) ; err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Resetting database:" , err )
os . Exit ( exitError )
2019-02-02 10:11:42 +01:00
}
2014-09-02 13:08:24 +02:00
return
2014-08-03 09:41:08 +02:00
}
2017-01-25 08:33:35 +01:00
if innerProcess || options . noRestart {
2015-12-17 23:40:46 +01:00
syncthingMain ( options )
2014-09-02 13:08:24 +02:00
} else {
2015-12-17 23:40:46 +01:00
monitorMain ( options )
2014-09-02 13:08:24 +02:00
}
}
2019-02-14 21:29:14 +01:00
func openGUI ( ) error {
cfg , err := loadOrDefaultConfig ( )
if err != nil {
return err
}
2015-12-16 16:11:01 +01:00
if cfg . GUI ( ) . Enabled {
2019-02-02 10:11:42 +01:00
if err := openURL ( cfg . GUI ( ) . URL ( ) ) ; err != nil {
2019-02-14 21:29:14 +01:00
return err
2019-02-02 10:11:42 +01:00
}
2015-12-16 16:11:01 +01:00
} else {
l . Warnln ( "Browser: GUI is currently disabled" )
}
2019-02-14 21:29:14 +01:00
return nil
2015-12-16 16:11:01 +01:00
}
2019-02-14 21:29:14 +01:00
func generate ( generateDir string ) error {
2017-08-19 16:36:56 +02:00
dir , err := fs . ExpandTilde ( generateDir )
2015-11-22 07:34:04 +01:00
if err != nil {
2019-02-14 21:29:14 +01:00
return err
}
if err := ensureDir ( dir , 0700 ) ; err != nil {
return err
2015-11-22 07:34:04 +01:00
}
certFile , keyFile := filepath . Join ( dir , "cert.pem" ) , filepath . Join ( dir , "key.pem" )
cert , err := tls . LoadX509KeyPair ( certFile , keyFile )
if err == nil {
l . Warnln ( "Key exists; will not overwrite." )
l . Infoln ( "Device ID:" , protocol . NewDeviceID ( cert . Certificate [ 0 ] ) )
} else {
2018-10-21 07:17:50 +02:00
cert , err = tlsutil . NewCertificate ( certFile , keyFile , tlsDefaultCommonName )
2015-11-22 07:34:04 +01:00
if err != nil {
2019-02-14 21:29:14 +01:00
return errors . Wrap ( err , "create certificate" )
2015-11-22 07:34:04 +01:00
}
myID = protocol . NewDeviceID ( cert . Certificate [ 0 ] )
if err != nil {
2019-02-14 21:29:14 +01:00
return errors . Wrap ( err , "load certificate" )
2015-11-22 07:34:04 +01:00
}
if err == nil {
l . Infoln ( "Device ID:" , protocol . NewDeviceID ( cert . Certificate [ 0 ] ) )
}
}
cfgFile := filepath . Join ( dir , "config.xml" )
if _ , err := os . Stat ( cfgFile ) ; err == nil {
l . Warnln ( "Config exists; will not overwrite." )
2019-02-14 21:29:14 +01:00
return nil
}
cfg , err := defaultConfig ( cfgFile )
if err != nil {
return err
2015-11-22 07:34:04 +01:00
}
err = cfg . Save ( )
if err != nil {
2019-02-14 21:29:14 +01:00
return errors . Wrap ( err , "save config" )
2015-11-22 07:34:04 +01:00
}
2019-02-14 21:29:14 +01:00
return nil
2015-11-22 07:34:04 +01:00
}
2015-10-03 17:25:21 +02:00
func debugFacilities ( ) string {
facilities := l . Facilities ( )
// Get a sorted list of names
var names [ ] string
maxLen := 0
for name := range facilities {
names = append ( names , name )
if len ( name ) > maxLen {
maxLen = len ( name )
}
}
sort . Strings ( names )
// Format the choices
b := new ( bytes . Buffer )
for _ , name := range names {
fmt . Fprintf ( b , " %-*s - %s\n" , maxLen , name , facilities [ name ] )
}
return b . String ( )
}
2015-12-16 20:29:37 +01:00
func checkUpgrade ( ) upgrade . Release {
2017-10-21 11:00:24 +02:00
cfg , _ := loadOrDefaultConfig ( )
2017-01-27 13:17:06 +01:00
opts := cfg . Options ( )
2019-02-12 07:58:24 +01:00
release , err := upgrade . LatestRelease ( opts . ReleasesURL , build . Version , opts . UpgradeToPreReleases )
2015-12-16 20:29:37 +01:00
if err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Upgrade:" , err )
os . Exit ( exitError )
2015-12-16 20:29:37 +01:00
}
2019-02-12 07:58:24 +01:00
if upgrade . CompareVersions ( release . Tag , build . Version ) <= 0 {
2015-12-16 20:29:37 +01:00
noUpgradeMessage := "No upgrade available (current %q >= latest %q)."
2019-02-12 07:58:24 +01:00
l . Infof ( noUpgradeMessage , build . Version , release . Tag )
2015-12-16 20:29:37 +01:00
os . Exit ( exitNoUpgradeAvailable )
}
2019-02-12 07:58:24 +01:00
l . Infof ( "Upgrade available (current %q < latest %q)" , build . Version , release . Tag )
2015-12-16 20:29:37 +01:00
return release
}
func performUpgrade ( release upgrade . Release ) {
// Use leveldb database locks to protect against concurrent upgrades
2019-07-14 12:43:13 +02:00
_ , err := syncthing . OpenGoleveldb ( locations . Get ( locations . Database ) )
2015-12-16 20:29:37 +01:00
if err == nil {
err = upgrade . To ( release )
if err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Upgrade:" , err )
os . Exit ( exitError )
2015-12-16 20:29:37 +01:00
}
2016-01-16 23:01:57 +01:00
l . Infof ( "Upgraded to %q" , release . Tag )
2015-12-16 20:29:37 +01:00
} else {
l . Infoln ( "Attempting upgrade through running Syncthing..." )
err = upgradeViaRest ( )
if err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Upgrade:" , err )
os . Exit ( exitError )
2015-12-16 20:29:37 +01:00
}
2016-01-16 23:01:57 +01:00
l . Infoln ( "Syncthing upgrading" )
2015-12-16 20:29:37 +01:00
os . Exit ( exitUpgrading )
}
}
2015-04-30 21:33:32 +02:00
func upgradeViaRest ( ) error {
2017-10-21 11:00:24 +02:00
cfg , _ := loadOrDefaultConfig ( )
2016-05-28 16:08:26 +02:00
u , err := url . Parse ( cfg . GUI ( ) . URL ( ) )
if err != nil {
return err
}
u . Path = path . Join ( u . Path , "rest/system/upgrade" )
target := u . String ( )
r , _ := http . NewRequest ( "POST" , target , nil )
2016-02-02 11:12:25 +01:00
r . Header . Set ( "X-API-Key" , cfg . GUI ( ) . APIKey )
2015-04-30 21:33:32 +02:00
tr := & http . Transport {
2015-10-13 20:52:22 +02:00
Dial : dialer . Dial ,
Proxy : http . ProxyFromEnvironment ,
2015-04-30 21:33:32 +02:00
TLSClientConfig : & tls . Config { InsecureSkipVerify : true } ,
}
client := & http . Client {
Transport : tr ,
Timeout : 60 * time . Second ,
}
resp , err := client . Do ( r )
if err != nil {
return err
}
if resp . StatusCode != 200 {
bs , err := ioutil . ReadAll ( resp . Body )
defer resp . Body . Close ( )
if err != nil {
return err
}
return errors . New ( string ( bs ) )
}
return err
}
2015-12-17 23:40:46 +01:00
func syncthingMain ( runtimeOptions RuntimeOptions ) {
2019-07-14 12:43:13 +02:00
cfg , err := loadConfigAtStartup ( runtimeOptions . allowNewerConfig )
if err != nil {
l . Warnln ( "Failed to initialize config:" , err )
os . Exit ( exitError )
2015-04-30 20:21:48 +02:00
}
2019-07-14 12:43:13 +02:00
if runtimeOptions . unpaused {
setPauseState ( cfg , false )
} else if runtimeOptions . paused {
setPauseState ( cfg , true )
2014-01-10 00:09:27 +01:00
}
2017-02-25 09:12:13 +01:00
// Ensure that we have a certificate and key.
2019-02-12 07:58:24 +01:00
cert , err := tls . LoadX509KeyPair (
locations . Get ( locations . CertFile ) ,
locations . Get ( locations . KeyFile ) ,
)
2013-12-15 11:43:31 +01:00
if err != nil {
2015-11-27 09:09:39 +01:00
l . Infof ( "Generating ECDSA key and certificate for %s..." , tlsDefaultCommonName )
2019-02-12 07:58:24 +01:00
cert , err = tlsutil . NewCertificate (
locations . Get ( locations . CertFile ) ,
locations . Get ( locations . KeyFile ) ,
tlsDefaultCommonName ,
)
2014-09-20 15:42:20 +02:00
if err != nil {
2019-07-14 12:43:13 +02:00
l . Warnln ( "Failed to generate certificate:" , err )
os . Exit ( 1 )
2014-09-20 15:42:20 +02:00
}
2013-12-15 11:43:31 +01:00
}
2019-02-12 07:58:24 +01:00
dbFile := locations . Get ( locations . Database )
2019-07-14 12:43:13 +02:00
ldb , err := syncthing . OpenGoleveldb ( dbFile )
2014-07-06 14:46:48 +02:00
if err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Error opening database:" , err )
2019-07-14 12:43:13 +02:00
os . Exit ( 1 )
2018-10-10 11:34:24 +02:00
}
2014-08-31 13:34:17 +02:00
2019-07-14 12:43:13 +02:00
appOpts := runtimeOptions . Options
if runtimeOptions . auditEnabled {
appOpts . AuditWriter = auditWriter ( runtimeOptions . auditFile )
2016-08-05 09:13:52 +02:00
}
2018-01-15 14:33:52 +01:00
if t := os . Getenv ( "STDEADLOCKTIMEOUT" ) ; t != "" {
2019-07-14 12:43:13 +02:00
secs , _ := strconv . Atoi ( t )
appOpts . DeadlockTimeoutS = secs
2015-04-08 14:35:03 +02:00
}
2019-07-14 12:43:13 +02:00
app := syncthing . New ( cfg , ldb , cert , appOpts )
2018-10-21 07:17:50 +02:00
2019-07-14 12:43:13 +02:00
setupSignalHandling ( app )
2018-10-21 07:17:50 +02:00
2019-07-14 12:43:13 +02:00
if len ( os . Getenv ( "GOMAXPROCS" ) ) == 0 {
runtime . GOMAXPROCS ( runtime . NumCPU ( ) )
2015-09-20 15:30:25 +02:00
}
2015-12-17 23:40:46 +01:00
if runtimeOptions . cpuProfile {
2014-08-13 14:38:23 +02:00
f , err := os . Create ( fmt . Sprintf ( "cpu-%d.pprof" , os . Getpid ( ) ) )
2014-04-14 12:13:50 +02:00
if err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Creating profile:" , err )
os . Exit ( exitError )
2019-02-02 10:11:42 +01:00
}
if err := pprof . StartCPUProfile ( f ) ; err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Starting profile:" , err )
os . Exit ( exitError )
2014-04-14 12:13:50 +02:00
}
}
2017-11-07 08:20:19 +01:00
if opts := cfg . Options ( ) ; opts . RestartOnWakeup {
2019-07-14 12:43:13 +02:00
go standbyMonitor ( app )
2014-09-10 22:24:53 +02:00
}
2014-08-27 23:38:36 +02:00
2017-01-30 22:33:07 +01:00
// Candidate builds should auto upgrade. Make sure the option is set,
// unless we are in a build where it's disabled or the STNOUPGRADE
// environment variable is set.
2019-07-14 12:43:13 +02:00
if build . IsCandidate && ! upgrade . DisabledByCompilation && ! runtimeOptions . NoUpgrade {
2017-01-30 22:33:07 +01:00
l . Infoln ( "Automatic upgrade is always enabled for candidate releases." )
2017-11-07 08:20:19 +01:00
if opts := cfg . Options ( ) ; opts . AutoUpgradeIntervalH == 0 || opts . AutoUpgradeIntervalH > 24 {
2017-01-30 22:33:07 +01:00
opts . AutoUpgradeIntervalH = 12
2017-04-10 15:56:52 +02:00
// Set the option into the config as well, as the auto upgrade
// loop expects to read a valid interval from there.
2019-02-02 12:16:27 +01:00
cfg . SetOptions ( opts )
cfg . Save ( )
2017-01-30 22:33:07 +01:00
}
// We don't tweak the user's choice of upgrading to pre-releases or
// not, as otherwise they cannot step off the candidate channel.
}
2017-11-07 08:20:19 +01:00
if opts := cfg . Options ( ) ; opts . AutoUpgradeIntervalH > 0 {
2019-07-14 12:43:13 +02:00
if runtimeOptions . NoUpgrade {
2014-11-26 19:48:31 +01:00
l . Infof ( "No automatic upgrades; STNOUPGRADE environment variable defined." )
2014-10-23 19:09:53 +02:00
} else {
2019-07-14 12:43:13 +02:00
go autoUpgrade ( cfg , app )
2014-10-23 19:09:53 +02:00
}
2014-09-26 00:51:12 +02:00
}
2019-07-14 12:43:13 +02:00
app . Start ( )
2014-07-13 21:07:24 +02:00
2015-04-07 09:25:28 +02:00
cleanConfigDirectory ( )
2019-07-14 12:43:13 +02:00
if cfg . Options ( ) . StartBrowser && ! runtimeOptions . noBrowser && ! runtimeOptions . stRestarting {
// Can potentially block if the utility we are invoking doesn't
// fork, and just execs, hence keep it in its own routine.
go func ( ) { _ = openURL ( cfg . GUI ( ) . URL ( ) ) } ( )
2019-06-17 14:27:25 +02:00
}
2015-04-25 11:19:53 +02:00
2019-07-14 12:43:13 +02:00
status := app . Wait ( )
2015-07-20 15:34:40 +02:00
2015-12-17 23:40:46 +01:00
if runtimeOptions . cpuProfile {
2015-07-20 15:34:40 +02:00
pprof . StopCPUProfile ( )
}
2019-07-14 12:43:13 +02:00
os . Exit ( int ( status ) )
2014-05-24 12:28:36 +02:00
}
2019-07-14 12:43:13 +02:00
func setupSignalHandling ( app * syncthing . App ) {
2015-12-14 09:57:49 +01:00
// Exit cleanly with "restarting" code on SIGHUP.
restartSign := make ( chan os . Signal , 1 )
sigHup := syscall . Signal ( 1 )
signal . Notify ( restartSign , sigHup )
go func ( ) {
<- restartSign
2019-07-14 12:43:13 +02:00
app . Stop ( syncthing . ExitRestart )
2015-12-14 09:57:49 +01:00
} ( )
// 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
2019-07-14 12:43:13 +02:00
app . Stop ( syncthing . ExitSuccess )
2015-12-14 09:57:49 +01:00
} ( )
}
2019-02-26 09:09:25 +01:00
func loadOrDefaultConfig ( ) ( config . Wrapper , error ) {
2019-02-12 07:58:24 +01:00
cfgFile := locations . Get ( locations . ConfigFile )
2015-12-19 00:39:36 +01:00
cfg , err := config . Load ( cfgFile , myID )
2015-09-29 20:05:22 +02:00
if err != nil {
2019-02-14 21:29:14 +01:00
cfg , err = defaultConfig ( cfgFile )
2015-09-29 20:05:22 +02:00
}
2015-12-19 00:39:36 +01:00
return cfg , err
}
2019-03-12 08:12:08 +01:00
func loadConfigAtStartup ( allowNewerConfig bool ) ( config . Wrapper , error ) {
2019-02-12 07:58:24 +01:00
cfgFile := locations . Get ( locations . ConfigFile )
2017-10-21 11:00:24 +02:00
cfg , err := config . Load ( cfgFile , myID )
2015-12-19 00:39:36 +01:00
if os . IsNotExist ( err ) {
2019-02-14 21:29:14 +01:00
cfg , err = defaultConfig ( cfgFile )
if err != nil {
return nil , errors . Wrap ( err , "failed to generate default config" )
}
err = cfg . Save ( )
if err != nil {
return nil , errors . Wrap ( err , "failed to save default config" )
}
l . Infof ( "Default config saved. Edit %s to taste (with Syncthing stopped) or use the GUI" , cfg . ConfigPath ( ) )
2017-10-21 11:00:24 +02:00
} else if err == io . EOF {
2019-02-14 21:29:14 +01:00
return nil , errors . New ( "Failed to load config: unexpected end of file. Truncated or empty configuration?" )
2015-12-19 00:39:36 +01:00
} else if err != nil {
2019-02-14 21:29:14 +01:00
return nil , errors . Wrap ( err , "failed to load config" )
2015-09-29 20:05:22 +02:00
}
2016-11-12 10:34:18 +01:00
if cfg . RawCopy ( ) . OriginalVersion != config . CurrentVersion {
2019-03-12 09:20:47 +01:00
if cfg . RawCopy ( ) . OriginalVersion == config . CurrentVersion + 1101 {
l . Infof ( "Now, THAT's what we call a config from the future! Don't worry. As long as you hit that wire with the connecting hook at precisely eighty-eight miles per hour the instant the lightning strikes the tower... everything will be fine." )
}
2019-03-12 08:12:08 +01:00
if cfg . RawCopy ( ) . OriginalVersion > config . CurrentVersion && ! allowNewerConfig {
return nil , fmt . Errorf ( "Config file version (%d) is newer than supported version (%d). If this is expected, use -allow-newer-config to override." , cfg . RawCopy ( ) . OriginalVersion , config . CurrentVersion )
}
2015-12-24 01:12:24 +01:00
err = archiveAndSaveConfig ( cfg )
if err != nil {
2019-02-14 21:29:14 +01:00
return nil , errors . Wrap ( err , "config archive" )
2015-12-24 01:12:24 +01:00
}
2015-09-29 20:05:22 +02:00
}
2019-02-14 21:29:14 +01:00
return cfg , nil
2015-09-29 20:05:22 +02:00
}
2019-02-26 09:09:25 +01:00
func archiveAndSaveConfig ( cfg config . Wrapper ) error {
2016-09-03 23:29:32 +02:00
// Copy the existing config to an archive copy
2016-11-12 10:34:18 +01:00
archivePath := cfg . ConfigPath ( ) + fmt . Sprintf ( ".v%d" , cfg . RawCopy ( ) . OriginalVersion )
2015-12-24 01:12:24 +01:00
l . Infoln ( "Archiving a copy of old config file format at:" , archivePath )
2016-09-03 23:29:32 +02:00
if err := copyFile ( cfg . ConfigPath ( ) , archivePath ) ; err != nil {
2015-12-24 01:12:24 +01:00
return err
2015-09-29 20:05:22 +02:00
}
2016-09-03 23:29:32 +02:00
// Do a regular atomic config sve
2015-12-24 01:12:24 +01:00
return cfg . Save ( )
2015-09-29 20:05:22 +02:00
}
2016-09-03 23:29:32 +02:00
func copyFile ( src , dst string ) error {
bs , err := ioutil . ReadFile ( src )
if err != nil {
return err
}
if err := ioutil . WriteFile ( dst , bs , 0600 ) ; err != nil {
// Attempt to clean up
os . Remove ( dst )
return err
}
return nil
}
2019-07-14 12:43:13 +02:00
func auditWriter ( auditFile string ) io . Writer {
2017-01-03 09:54:28 +01:00
var fd io . Writer
var err error
var auditDest string
var auditFlags int
if auditFile == "-" {
fd = os . Stdout
auditDest = "stdout"
} else if auditFile == "--" {
fd = os . Stderr
auditDest = "stderr"
} else {
if auditFile == "" {
2019-02-12 07:58:24 +01:00
auditFile = locations . GetTimestamped ( locations . AuditLog )
2017-01-03 09:54:28 +01:00
auditFlags = os . O_WRONLY | os . O_CREATE | os . O_EXCL
} else {
auditFlags = os . O_WRONLY | os . O_CREATE | os . O_APPEND
}
fd , err = os . OpenFile ( auditFile , auditFlags , 0600 )
if err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Audit:" , err )
os . Exit ( exitError )
2017-01-03 09:54:28 +01:00
}
auditDest = auditFile
2015-04-25 11:21:47 +02:00
}
2017-01-03 09:54:28 +01:00
l . Infoln ( "Audit log in" , auditDest )
2015-04-25 11:21:47 +02:00
2019-07-14 12:43:13 +02:00
return fd
2014-10-10 17:32:43 +02:00
}
2019-02-26 09:09:25 +01:00
func defaultConfig ( cfgFile string ) ( config . Wrapper , error ) {
2019-02-14 21:29:14 +01:00
newCfg , err := config . NewWithFreePorts ( myID )
if err != nil {
return nil , err
}
2017-10-21 11:00:24 +02:00
2019-02-02 12:43:57 +01:00
if noDefaultFolder {
2016-01-09 02:11:06 +01:00
l . Infoln ( "We will skip creation of a default folder on first start since the proper envvar is set" )
2019-02-14 21:29:14 +01:00
return config . Wrap ( cfgFile , newCfg ) , nil
2016-01-09 02:11:06 +01:00
}
2015-11-07 09:47:31 +01:00
2019-02-12 07:58:24 +01:00
newCfg . Folders = append ( newCfg . Folders , config . NewFolderConfiguration ( myID , "default" , "Default Folder" , fs . FilesystemTypeBasic , locations . Get ( locations . DefFolder ) ) )
2019-02-02 12:43:57 +01:00
l . Infoln ( "Default folder created and/or linked to new config" )
2019-02-14 21:29:14 +01:00
return config . Wrap ( cfgFile , newCfg ) , nil
2014-10-10 17:32:43 +02:00
}
2015-04-03 20:06:03 +02:00
func resetDB ( ) error {
2019-02-12 07:58:24 +01:00
return os . RemoveAll ( locations . Get ( locations . Database ) )
2014-07-15 14:27:46 +02:00
}
2019-02-14 21:29:14 +01:00
func ensureDir ( dir string , mode fs . FileMode ) error {
2017-08-19 16:36:56 +02:00
fs := fs . NewFilesystem ( fs . FilesystemTypeBasic , dir )
err := fs . MkdirAll ( "." , mode )
2015-12-16 21:03:20 +01:00
if err != nil {
2019-02-14 21:29:14 +01:00
return err
2015-12-16 21:03:20 +01:00
}
2017-08-19 16:36:56 +02:00
if fi , err := fs . Stat ( "." ) ; err == nil {
2015-12-21 08:35:24 +01:00
// Apprently the stat may fail even though the mkdirall passed. If it
// does, we'll just assume things are in order and let other things
// fail (like loading or creating the config...).
currentMode := fi . Mode ( ) & 0777
if currentMode != mode {
2017-08-19 16:36:56 +02:00
err := fs . Chmod ( "." , mode )
2015-12-21 08:35:24 +01:00
// This can fail on crappy filesystems, nothing we can do about it.
if err != nil {
l . Warnln ( err )
}
2014-09-20 15:41:52 +02:00
}
2013-12-15 11:43:31 +01:00
}
2019-02-14 21:29:14 +01:00
return nil
2013-12-15 11:43:31 +01:00
}
2019-07-14 12:43:13 +02:00
func standbyMonitor ( app * syncthing . App ) {
2016-12-17 15:37:11 +01:00
restartDelay := 60 * time . Second
2014-08-27 23:38:36 +02:00
now := time . Now ( )
for {
time . Sleep ( 10 * time . Second )
if time . Since ( now ) > 2 * time . Minute {
2014-09-27 14:44:15 +02:00
l . Infof ( "Paused state detected, possibly woke up from standby. Restarting in %v." , restartDelay )
2014-09-10 22:20:03 +02:00
// We most likely just woke from standby. If we restart
// immediately chances are we won't have networking ready. Give
// things a moment to stabilize.
2014-09-11 20:25:08 +02:00
time . Sleep ( restartDelay )
2014-09-10 22:20:03 +02:00
2019-07-14 12:43:13 +02:00
app . Stop ( syncthing . ExitRestart )
2014-09-10 22:20:03 +02:00
return
2014-08-27 23:38:36 +02:00
}
now = time . Now ( )
}
}
2014-09-26 00:51:12 +02:00
2019-07-14 12:43:13 +02:00
func autoUpgrade ( cfg config . Wrapper , app * syncthing . App ) {
2014-12-27 00:12:12 +01:00
timer := time . NewTimer ( 0 )
sub := events . Default . Subscribe ( events . DeviceConnected )
2014-09-26 00:51:12 +02:00
for {
2014-12-27 00:12:12 +01:00
select {
case event := <- sub . C ( ) :
data , ok := event . Data . ( map [ string ] string )
2019-02-12 07:58:24 +01:00
if ! ok || data [ "clientName" ] != "syncthing" || upgrade . CompareVersions ( data [ "clientVersion" ] , build . Version ) != upgrade . Newer {
2014-12-27 00:12:12 +01:00
continue
}
2019-02-12 07:58:24 +01:00
l . Infof ( "Connected to device %s with a newer version (current %q < remote %q). Checking for upgrades." , data [ "id" ] , build . Version , data [ "clientVersion" ] )
2014-12-27 00:12:12 +01:00
case <- timer . C :
2014-09-26 00:51:12 +02:00
}
2017-04-10 15:56:52 +02:00
2017-01-27 13:17:06 +01:00
opts := cfg . Options ( )
2017-04-10 15:56:52 +02:00
checkInterval := time . Duration ( opts . AutoUpgradeIntervalH ) * time . Hour
if checkInterval < time . Hour {
// We shouldn't be here if AutoUpgradeIntervalH < 1, but for
// safety's sake.
checkInterval = time . Hour
}
2019-02-12 07:58:24 +01:00
rel , err := upgrade . LatestRelease ( opts . ReleasesURL , build . Version , opts . UpgradeToPreReleases )
2014-10-01 00:01:32 +02:00
if err == upgrade . ErrUpgradeUnsupported {
2014-12-27 00:12:12 +01:00
events . Default . Unsubscribe ( sub )
2014-10-01 00:01:32 +02:00
return
}
2014-09-26 00:51:12 +02:00
if err != nil {
2014-09-30 17:38:12 +02:00
// Don't complain too loudly here; we might simply not have
// internet connectivity, or the upgrade server might be down.
l . Infoln ( "Automatic upgrade:" , err )
2017-04-10 15:56:52 +02:00
timer . Reset ( checkInterval )
2014-09-26 00:51:12 +02:00
continue
}
2019-02-12 07:58:24 +01:00
if upgrade . CompareVersions ( rel . Tag , build . Version ) != upgrade . Newer {
2014-12-29 12:21:08 +01:00
// Skip equal, older or majorly newer (incompatible) versions
2017-04-10 15:56:52 +02:00
timer . Reset ( checkInterval )
2014-09-26 00:51:12 +02:00
continue
}
2019-02-12 07:58:24 +01:00
l . Infof ( "Automatic upgrade (current %q < latest %q)" , build . Version , rel . Tag )
2014-12-08 16:36:15 +01:00
err = upgrade . To ( rel )
2014-09-26 00:51:12 +02:00
if err != nil {
l . Warnln ( "Automatic upgrade:" , err )
2017-04-10 15:56:52 +02:00
timer . Reset ( checkInterval )
2014-09-26 00:51:12 +02:00
continue
}
2014-12-27 00:12:12 +01:00
events . Default . Unsubscribe ( sub )
2014-09-26 00:51:12 +02:00
l . Warnf ( "Automatically upgraded to version %q. Restarting in 1 minute." , rel . Tag )
time . Sleep ( time . Minute )
2019-07-14 12:43:13 +02:00
app . Stop ( syncthing . ExitUpgrade )
2014-09-26 00:51:12 +02:00
return
}
}
2015-04-07 09:25:28 +02:00
// cleanConfigDirectory removes old, unused configuration and index formats, a
// suitable time after they have gone out of fashion.
func cleanConfigDirectory ( ) {
patterns := map [ string ] time . Duration {
2016-08-22 14:19:19 +02:00
"panic-*.log" : 7 * 24 * time . Hour , // keep panic logs for a week
"audit-*.log" : 7 * 24 * time . Hour , // keep audit logs for a week
"index" : 14 * 24 * time . Hour , // keep old index format for two weeks
"index-v0.11.0.db" : 14 * 24 * time . Hour , // keep old index format for two weeks
"index-v0.13.0.db" : 14 * 24 * time . Hour , // keep old index format for two weeks
"index*.converted" : 14 * 24 * time . Hour , // keep old converted indexes for two weeks
"config.xml.v*" : 30 * 24 * time . Hour , // old config versions for a month
"*.idx.gz" : 30 * 24 * time . Hour , // these should for sure no longer exist
"backup-of-v0.8" : 30 * 24 * time . Hour , // these neither
"tmp-index-sorter.*" : time . Minute , // these should never exist on startup
2018-10-01 17:23:46 +02:00
"support-bundle-*" : 30 * 24 * time . Hour , // keep old support bundle zip or folder for a month
2015-04-07 09:25:28 +02:00
}
for pat , dur := range patterns {
2019-02-12 07:58:24 +01:00
fs := fs . NewFilesystem ( fs . FilesystemTypeBasic , locations . GetBaseDir ( locations . ConfigBaseDir ) )
2017-08-19 16:36:56 +02:00
files , err := fs . Glob ( pat )
2015-04-07 09:25:28 +02:00
if err != nil {
l . Infoln ( "Cleaning:" , err )
continue
}
for _ , file := range files {
2017-08-19 16:36:56 +02:00
info , err := fs . Lstat ( file )
2015-04-07 09:25:28 +02:00
if err != nil {
l . Infoln ( "Cleaning:" , err )
continue
}
if time . Since ( info . ModTime ( ) ) > dur {
2017-08-19 16:36:56 +02:00
if err = fs . RemoveAll ( file ) ; err != nil {
2015-04-07 09:25:28 +02:00
l . Infoln ( "Cleaning:" , err )
} else {
l . Infoln ( "Cleaned away old file" , filepath . Base ( file ) )
}
}
}
}
}
2015-04-09 12:53:13 +02:00
2018-03-28 19:02:43 +02:00
func showPaths ( options RuntimeOptions ) {
2019-02-12 07:58:24 +01:00
fmt . Printf ( "Configuration file:\n\t%s\n\n" , locations . Get ( locations . ConfigFile ) )
fmt . Printf ( "Database directory:\n\t%s\n\n" , locations . Get ( locations . Database ) )
fmt . Printf ( "Device private key & certificate files:\n\t%s\n\t%s\n\n" , locations . Get ( locations . KeyFile ) , locations . Get ( locations . CertFile ) )
fmt . Printf ( "HTTPS private key & certificate files:\n\t%s\n\t%s\n\n" , locations . Get ( locations . HTTPSKeyFile ) , locations . Get ( locations . HTTPSCertFile ) )
2018-03-28 19:02:43 +02:00
fmt . Printf ( "Log file:\n\t%s\n\n" , options . logFile )
2019-07-14 12:43:13 +02:00
fmt . Printf ( "GUI override directory:\n\t%s\n\n" , options . AssetDir )
2019-02-12 07:58:24 +01:00
fmt . Printf ( "Default sync folder directory:\n\t%s\n\n" , locations . Get ( locations . DefFolder ) )
2016-02-02 10:27:01 +01:00
}
2016-12-21 19:41:25 +01:00
2019-02-26 09:09:25 +01:00
func setPauseState ( cfg config . Wrapper , paused bool ) {
2016-12-21 19:41:25 +01:00
raw := cfg . RawCopy ( )
for i := range raw . Devices {
raw . Devices [ i ] . Paused = paused
}
for i := range raw . Folders {
raw . Folders [ i ] . Paused = paused
}
2017-12-07 08:08:24 +01:00
if _ , err := cfg . Replace ( raw ) ; err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Cannot adjust paused state:" , err )
os . Exit ( exitError )
2016-12-21 19:41:25 +01:00
}
}