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 (
2019-10-16 20:31:46 +02:00
tlsDefaultCommonName = "syncthing"
deviceCertLifetimeDays = 20 * 365
2015-03-26 23:26:51 +01:00
)
2015-03-05 15:58:16 +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
2019-11-28 12:26:14 +01:00
logMaxSize int
logMaxFiles int
2019-03-12 08:12:08 +01:00
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 ,
2019-11-28 12:26:14 +01:00
logMaxSize : 10 << 20 , // 10 MiB
logMaxFiles : 3 , // plus the current one
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." )
2019-11-28 12:26:14 +01:00
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)." )
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" )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
2017-09-25 08:05:21 +02:00
}
2019-07-17 07:19:14 +02:00
fmt . Println ( protocol . NewDeviceID ( cert . Certificate [ 0 ] ) )
2017-09-25 08:05:21 +02:00
return
}
2015-12-17 23:40:46 +01:00
if options . browserOnly {
2019-07-17 07:19:14 +02:00
if err := openGUI ( protocol . EmptyDeviceID ) ; err != nil {
2019-02-14 21:29:14 +01:00
l . Warnln ( "Failed to open web UI:" , err )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
2019-02-14 21:29:14 +01:00
}
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
2019-02-14 21:29:14 +01:00
}
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
2019-02-14 21:29:14 +01:00
}
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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-07-17 07:19:14 +02:00
func openGUI ( myID protocol . DeviceID ) error {
2019-08-15 16:29:37 +02:00
cfg , err := loadOrDefaultConfig ( myID , events . NoopLogger )
2019-02-14 21:29:14 +01:00
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
}
2019-07-17 07:19:14 +02:00
var myID protocol . DeviceID
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." )
} else {
2019-10-16 20:31:46 +02:00
cert , err = tlsutil . NewCertificate ( certFile , keyFile , tlsDefaultCommonName , deviceCertLifetimeDays )
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
}
}
2019-07-17 07:19:14 +02:00
myID = protocol . NewDeviceID ( cert . Certificate [ 0 ] )
l . Infoln ( "Device ID:" , myID )
2015-11-22 07:34:04 +01:00
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
}
2019-08-15 16:29:37 +02:00
cfg , err := syncthing . DefaultConfig ( cfgFile , myID , events . NoopLogger , noDefaultFolder )
2019-02-14 21:29:14 +01:00
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 {
2019-08-15 16:29:37 +02:00
cfg , _ := loadOrDefaultConfig ( protocol . EmptyDeviceID , events . NoopLogger )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitNoUpgradeAvailable . AsInt ( ) )
2015-12-16 20:29:37 +01:00
}
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-12-12 16:50:09 +01:00
_ , err := syncthing . OpenDBBackend ( locations . Get ( locations . Database ) , config . TuningAuto )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
2015-12-16 20:29:37 +01:00
}
2016-01-16 23:01:57 +01:00
l . Infoln ( "Syncthing upgrading" )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitUpgrade . AsInt ( ) )
2015-12-16 20:29:37 +01:00
}
}
2015-04-30 21:33:32 +02:00
func upgradeViaRest ( ) error {
2019-08-15 16:29:37 +02:00
cfg , _ := loadOrDefaultConfig ( protocol . EmptyDeviceID , events . NoopLogger )
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 {
2019-11-26 08:39:51 +01:00
DialContext : dialer . DialContext ,
2015-10-13 20:52:22 +02:00
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-27 11:58:39 +02:00
// Set a log prefix similar to the ID we will have later on, or early log
// lines look ugly.
l . SetPrefix ( "[start] " )
// Print our version information up front, so any crash that happens
// early etc. will have it available.
l . Infoln ( build . LongVersion )
2017-02-25 09:12:13 +01:00
// Ensure that we have a certificate and key.
2019-07-23 23:39:20 +02:00
cert , err := syncthing . LoadOrGenerateCertificate (
2019-02-12 07:58:24 +01:00
locations . Get ( locations . CertFile ) ,
locations . Get ( locations . KeyFile ) ,
)
2013-12-15 11:43:31 +01:00
if err != nil {
2019-07-23 23:39:20 +02:00
l . Warnln ( "Failed to load/generate certificate:" , err )
os . Exit ( 1 )
2013-12-15 11:43:31 +01:00
}
2019-07-17 07:19:14 +02:00
2019-08-15 16:29:37 +02:00
evLogger := events . NewLogger ( )
go evLogger . Serve ( )
defer evLogger . Stop ( )
cfg , err := syncthing . LoadConfigAtStartup ( locations . Get ( locations . ConfigFile ) , cert , evLogger , runtimeOptions . allowNewerConfig , noDefaultFolder )
2019-07-17 07:19:14 +02:00
if err != nil {
l . Warnln ( "Failed to initialize config:" , err )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
2019-07-17 07:19:14 +02:00
}
if runtimeOptions . unpaused {
setPauseState ( cfg , false )
} else if runtimeOptions . paused {
setPauseState ( cfg , true )
}
2013-12-15 11:43:31 +01:00
2019-02-12 07:58:24 +01:00
dbFile := locations . Get ( locations . Database )
2019-12-12 16:50:09 +01:00
ldb , err := syncthing . OpenDBBackend ( dbFile , cfg . Options ( ) . DatabaseTuning )
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-08-15 16:29:37 +02:00
app := syncthing . New ( cfg , ldb , evLogger , 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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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-08-15 16:29:37 +02:00
go autoUpgrade ( cfg , app , evLogger )
2014-10-23 19:09:53 +02:00
}
2014-09-26 00:51:12 +02:00
}
2019-10-16 10:10:42 +02:00
if err := app . Start ( ) ; err != nil {
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
2019-10-16 10:10:42 +02:00
}
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-08-15 16:29:37 +02:00
func loadOrDefaultConfig ( myID protocol . DeviceID , evLogger events . Logger ) ( config . Wrapper , error ) {
2019-02-12 07:58:24 +01:00
cfgFile := locations . Get ( locations . ConfigFile )
2019-08-15 16:29:37 +02:00
cfg , err := config . Load ( cfgFile , myID , evLogger )
2015-12-19 00:39:36 +01:00
2015-09-29 20:05:22 +02:00
if err != nil {
2019-08-15 16:29:37 +02:00
cfg , err = syncthing . DefaultConfig ( cfgFile , myID , evLogger , noDefaultFolder )
2015-09-29 20:05:22 +02:00
}
2015-12-19 00:39:36 +01:00
return cfg , err
}
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
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
}
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-08-15 16:29:37 +02:00
func autoUpgrade ( cfg config . Wrapper , app * syncthing . App , evLogger events . Logger ) {
2014-12-27 00:12:12 +01:00
timer := time . NewTimer ( 0 )
2019-08-15 16:29:37 +02:00
sub := evLogger . 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 {
2019-08-15 16:29:37 +02:00
sub . Unsubscribe ( )
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
}
2019-08-15 16:29:37 +02:00
sub . Unsubscribe ( )
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 )
2019-11-06 07:09:58 +01:00
os . Exit ( syncthing . ExitError . AsInt ( ) )
2016-12-21 19:41:25 +01:00
}
}