main.go 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package main
  7. import (
  8. "bytes"
  9. "crypto/tls"
  10. "errors"
  11. "flag"
  12. "fmt"
  13. "io"
  14. "io/ioutil"
  15. "log"
  16. "net"
  17. "net/http"
  18. "net/url"
  19. "os"
  20. "os/signal"
  21. "path"
  22. "path/filepath"
  23. "regexp"
  24. "runtime"
  25. "runtime/pprof"
  26. "sort"
  27. "strconv"
  28. "strings"
  29. "syscall"
  30. "time"
  31. "github.com/syncthing/syncthing/lib/config"
  32. "github.com/syncthing/syncthing/lib/connections"
  33. "github.com/syncthing/syncthing/lib/db"
  34. "github.com/syncthing/syncthing/lib/dialer"
  35. "github.com/syncthing/syncthing/lib/discover"
  36. "github.com/syncthing/syncthing/lib/events"
  37. "github.com/syncthing/syncthing/lib/logger"
  38. "github.com/syncthing/syncthing/lib/model"
  39. "github.com/syncthing/syncthing/lib/osutil"
  40. "github.com/syncthing/syncthing/lib/protocol"
  41. "github.com/syncthing/syncthing/lib/rand"
  42. "github.com/syncthing/syncthing/lib/sha256"
  43. "github.com/syncthing/syncthing/lib/tlsutil"
  44. "github.com/syncthing/syncthing/lib/upgrade"
  45. "github.com/syncthing/syncthing/lib/weakhash"
  46. "github.com/thejerf/suture"
  47. _ "net/http/pprof" // Need to import this to support STPROFILER.
  48. )
  49. var (
  50. Version = "unknown-dev"
  51. Codename = "Dysprosium Dragonfly"
  52. BuildStamp = "0"
  53. BuildDate time.Time
  54. BuildHost = "unknown"
  55. BuildUser = "unknown"
  56. IsRelease bool
  57. IsCandidate bool
  58. IsBeta bool
  59. LongVersion string
  60. BuildTags []string
  61. allowedVersionExp = regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z0-9]+)*(\.\d+)*(\+\d+-g[0-9a-f]+)?(-[^\s]+)?$`)
  62. )
  63. const (
  64. exitSuccess = 0
  65. exitError = 1
  66. exitNoUpgradeAvailable = 2
  67. exitRestarting = 3
  68. exitUpgrading = 4
  69. )
  70. const (
  71. bepProtocolName = "bep/1.0"
  72. tlsDefaultCommonName = "syncthing"
  73. httpsRSABits = 2048
  74. bepRSABits = 0 // 384 bit ECDSA used instead
  75. defaultEventTimeout = time.Minute
  76. maxSystemErrors = 5
  77. initialSystemLog = 10
  78. maxSystemLog = 250
  79. )
  80. // The discovery results are sorted by their source priority.
  81. const (
  82. ipv6LocalDiscoveryPriority = iota
  83. ipv4LocalDiscoveryPriority
  84. globalDiscoveryPriority
  85. )
  86. func init() {
  87. if Version != "unknown-dev" {
  88. // If not a generic dev build, version string should come from git describe
  89. if !allowedVersionExp.MatchString(Version) {
  90. l.Fatalf("Invalid version string %q;\n\tdoes not match regexp %v", Version, allowedVersionExp)
  91. }
  92. }
  93. }
  94. func setBuildMetadata() {
  95. // Check for a clean release build. A release is something like
  96. // "v0.1.2", with an optional suffix of letters and dot separated
  97. // numbers like "-beta3.47". If there's more stuff, like a plus sign and
  98. // a commit hash and so on, then it's not a release. If it has a dash in
  99. // it, it's some sort of beta, release candidate or special build. If it
  100. // has "-rc." in it, like "v0.14.35-rc.42", then it's a candidate build.
  101. //
  102. // So, every build that is not a stable release build has IsBeta = true.
  103. // This is used to enable some extra debugging (the deadlock detector).
  104. //
  105. // Release candidate builds are also "betas" from this point of view and
  106. // will have that debugging enabled. In addition, some features are
  107. // forced for release candidates - auto upgrade, and usage reporting.
  108. exp := regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z]+[\d\.]+)?$`)
  109. IsRelease = exp.MatchString(Version)
  110. IsCandidate = strings.Contains(Version, "-rc.")
  111. IsBeta = strings.Contains(Version, "-")
  112. stamp, _ := strconv.Atoi(BuildStamp)
  113. BuildDate = time.Unix(int64(stamp), 0)
  114. date := BuildDate.UTC().Format("2006-01-02 15:04:05 MST")
  115. LongVersion = fmt.Sprintf(`syncthing %s "%s" (%s %s-%s) %s@%s %s`, Version, Codename, runtime.Version(), runtime.GOOS, runtime.GOARCH, BuildUser, BuildHost, date)
  116. if len(BuildTags) > 0 {
  117. LongVersion = fmt.Sprintf("%s [%s]", LongVersion, strings.Join(BuildTags, ", "))
  118. }
  119. }
  120. var (
  121. myID protocol.DeviceID
  122. stop = make(chan int)
  123. lans []*net.IPNet
  124. )
  125. const (
  126. usage = "syncthing [options]"
  127. extraUsage = `
  128. The -logflags value is a sum of the following:
  129. 1 Date
  130. 2 Time
  131. 4 Microsecond time
  132. 8 Long filename
  133. 16 Short filename
  134. I.e. to prefix each log line with date and time, set -logflags=3 (1 + 2 from
  135. above). The value 0 is used to disable all of the above. The default is to
  136. show time only (2).
  137. Development Settings
  138. --------------------
  139. The following environment variables modify Syncthing's behavior in ways that
  140. are mostly useful for developers. Use with care.
  141. STNODEFAULTFOLDER Don't create a default folder when starting for the first
  142. time. This variable will be ignored anytime after the first
  143. run.
  144. STGUIASSETS Directory to load GUI assets from. Overrides compiled in
  145. assets.
  146. STTRACE A comma separated string of facilities to trace. The valid
  147. facility strings listed below.
  148. STPROFILER Set to a listen address such as "127.0.0.1:9090" to start
  149. the profiler with HTTP access.
  150. STCPUPROFILE Write a CPU profile to cpu-$pid.pprof on exit.
  151. STHEAPPROFILE Write heap profiles to heap-$pid-$timestamp.pprof each time
  152. heap usage increases.
  153. STBLOCKPROFILE Write block profiles to block-$pid-$timestamp.pprof every 20
  154. seconds.
  155. STPERFSTATS Write running performance statistics to perf-$pid.csv. Not
  156. supported on Windows.
  157. STDEADLOCK Used for debugging internal deadlocks. Use only under
  158. direction of a developer.
  159. STDEADLOCKTIMEOUT Used for debugging internal deadlocks; sets debug
  160. sensitivity. Use only under direction of a developer.
  161. STDEADLOCKTHRESHOLD Used for debugging internal deadlocks; sets debug
  162. sensitivity. Use only under direction of a developer.
  163. STNORESTART Equivalent to the -no-restart argument. Disable the
  164. Syncthing monitor process which handles restarts for some
  165. configuration changes, upgrades, crashes and also log file
  166. writing (stdout is still written).
  167. STNOUPGRADE Disable automatic upgrades.
  168. STHASHING Select the SHA256 hashing package to use. Possible values
  169. are "standard" for the Go standard library implementation,
  170. "minio" for the github.com/minio/sha256-simd implementation,
  171. and blank (the default) for auto detection.
  172. GOMAXPROCS Set the maximum number of CPU cores to use. Defaults to all
  173. available CPU cores.
  174. GOGC Percentage of heap growth at which to trigger GC. Default is
  175. 100. Lower numbers keep peak memory usage down, at the price
  176. of CPU usage (i.e. performance).
  177. Debugging Facilities
  178. --------------------
  179. The following are valid values for the STTRACE variable:
  180. %s`
  181. )
  182. // Environment options
  183. var (
  184. noUpgradeFromEnv = os.Getenv("STNOUPGRADE") != ""
  185. innerProcess = os.Getenv("STNORESTART") != "" || os.Getenv("STMONITORED") != ""
  186. noDefaultFolder = os.Getenv("STNODEFAULTFOLDER") != ""
  187. )
  188. type RuntimeOptions struct {
  189. confDir string
  190. resetDatabase bool
  191. resetDeltaIdxs bool
  192. showVersion bool
  193. showPaths bool
  194. doUpgrade bool
  195. doUpgradeCheck bool
  196. upgradeTo string
  197. noBrowser bool
  198. browserOnly bool
  199. hideConsole bool
  200. logFile string
  201. auditEnabled bool
  202. auditFile string
  203. verbose bool
  204. paused bool
  205. unpaused bool
  206. guiAddress string
  207. guiAPIKey string
  208. generateDir string
  209. noRestart bool
  210. profiler string
  211. assetDir string
  212. cpuProfile bool
  213. stRestarting bool
  214. logFlags int
  215. }
  216. func defaultRuntimeOptions() RuntimeOptions {
  217. options := RuntimeOptions{
  218. noRestart: os.Getenv("STNORESTART") != "",
  219. profiler: os.Getenv("STPROFILER"),
  220. assetDir: os.Getenv("STGUIASSETS"),
  221. cpuProfile: os.Getenv("STCPUPROFILE") != "",
  222. stRestarting: os.Getenv("STRESTART") != "",
  223. logFlags: log.Ltime,
  224. }
  225. if os.Getenv("STTRACE") != "" {
  226. options.logFlags = log.Ltime | log.Ldate | log.Lmicroseconds | log.Lshortfile
  227. }
  228. if runtime.GOOS != "windows" {
  229. // On non-Windows, we explicitly default to "-" which means stdout. On
  230. // Windows, the blank options.logFile will later be replaced with the
  231. // default path, unless the user has manually specified "-" or
  232. // something else.
  233. options.logFile = "-"
  234. }
  235. return options
  236. }
  237. func parseCommandLineOptions() RuntimeOptions {
  238. options := defaultRuntimeOptions()
  239. flag.StringVar(&options.generateDir, "generate", "", "Generate key and config in specified dir, then exit")
  240. flag.StringVar(&options.guiAddress, "gui-address", options.guiAddress, "Override GUI address (e.g. \"http://192.0.2.42:8443\")")
  241. flag.StringVar(&options.guiAPIKey, "gui-apikey", options.guiAPIKey, "Override GUI API key")
  242. flag.StringVar(&options.confDir, "home", "", "Set configuration directory")
  243. flag.IntVar(&options.logFlags, "logflags", options.logFlags, "Select information in log line prefix (see below)")
  244. flag.BoolVar(&options.noBrowser, "no-browser", false, "Do not start browser")
  245. flag.BoolVar(&options.browserOnly, "browser-only", false, "Open GUI in browser")
  246. flag.BoolVar(&options.noRestart, "no-restart", options.noRestart, "Disable monitor process, managed restarts and log file writing")
  247. flag.BoolVar(&options.resetDatabase, "reset-database", false, "Reset the database, forcing a full rescan and resync")
  248. flag.BoolVar(&options.resetDeltaIdxs, "reset-deltas", false, "Reset delta index IDs, forcing a full index exchange")
  249. flag.BoolVar(&options.doUpgrade, "upgrade", false, "Perform upgrade")
  250. flag.BoolVar(&options.doUpgradeCheck, "upgrade-check", false, "Check for available upgrade")
  251. flag.BoolVar(&options.showVersion, "version", false, "Show version")
  252. flag.BoolVar(&options.showPaths, "paths", false, "Show configuration paths")
  253. flag.StringVar(&options.upgradeTo, "upgrade-to", options.upgradeTo, "Force upgrade directly from specified URL")
  254. flag.BoolVar(&options.auditEnabled, "audit", false, "Write events to audit file")
  255. flag.BoolVar(&options.verbose, "verbose", false, "Print verbose log output")
  256. flag.BoolVar(&options.paused, "paused", false, "Start with all devices and folders paused")
  257. flag.BoolVar(&options.unpaused, "unpaused", false, "Start with all devices and folders unpaused")
  258. flag.StringVar(&options.logFile, "logfile", options.logFile, "Log file name (use \"-\" for stdout)")
  259. flag.StringVar(&options.auditFile, "auditfile", options.auditFile, "Specify audit file (use \"-\" for stdout, \"--\" for stderr)")
  260. if runtime.GOOS == "windows" {
  261. // Allow user to hide the console window
  262. flag.BoolVar(&options.hideConsole, "no-console", false, "Hide console window")
  263. }
  264. longUsage := fmt.Sprintf(extraUsage, debugFacilities())
  265. flag.Usage = usageFor(flag.CommandLine, usage, longUsage)
  266. flag.Parse()
  267. if len(flag.Args()) > 0 {
  268. flag.Usage()
  269. os.Exit(2)
  270. }
  271. return options
  272. }
  273. func main() {
  274. setBuildMetadata()
  275. options := parseCommandLineOptions()
  276. l.SetFlags(options.logFlags)
  277. if options.guiAddress != "" {
  278. // The config picks this up from the environment.
  279. os.Setenv("STGUIADDRESS", options.guiAddress)
  280. }
  281. if options.guiAPIKey != "" {
  282. // The config picks this up from the environment.
  283. os.Setenv("STGUIAPIKEY", options.guiAPIKey)
  284. }
  285. // Check for options which are not compatible with each other. We have
  286. // to check logfile before it's set to the default below - we only want
  287. // to complain if they set -logfile explicitly, not if it's set to its
  288. // default location
  289. if options.noRestart && (options.logFile != "" && options.logFile != "-") {
  290. l.Fatalln("-logfile may not be used with -no-restart or STNORESTART")
  291. }
  292. if options.hideConsole {
  293. osutil.HideConsole()
  294. }
  295. if options.confDir != "" {
  296. // Not set as default above because the string can be really long.
  297. if !filepath.IsAbs(options.confDir) {
  298. var err error
  299. options.confDir, err = filepath.Abs(options.confDir)
  300. if err != nil {
  301. l.Fatalln(err)
  302. }
  303. }
  304. baseDirs["config"] = options.confDir
  305. }
  306. if err := expandLocations(); err != nil {
  307. l.Fatalln(err)
  308. }
  309. if options.logFile == "" {
  310. // Blank means use the default logfile location. We must set this
  311. // *after* expandLocations above.
  312. options.logFile = locations[locLogFile]
  313. }
  314. if options.assetDir == "" {
  315. // The asset dir is blank if STGUIASSETS wasn't set, in which case we
  316. // should look for extra assets in the default place.
  317. options.assetDir = locations[locGUIAssets]
  318. }
  319. if options.showVersion {
  320. fmt.Println(LongVersion)
  321. return
  322. }
  323. if options.showPaths {
  324. showPaths()
  325. return
  326. }
  327. if options.browserOnly {
  328. openGUI()
  329. return
  330. }
  331. if options.generateDir != "" {
  332. generate(options.generateDir)
  333. return
  334. }
  335. // Ensure that our home directory exists.
  336. ensureDir(baseDirs["config"], 0700)
  337. if options.upgradeTo != "" {
  338. err := upgrade.ToURL(options.upgradeTo)
  339. if err != nil {
  340. l.Fatalln("Upgrade:", err) // exits 1
  341. }
  342. l.Infoln("Upgraded from", options.upgradeTo)
  343. return
  344. }
  345. if options.doUpgradeCheck {
  346. checkUpgrade()
  347. return
  348. }
  349. if options.doUpgrade {
  350. release := checkUpgrade()
  351. performUpgrade(release)
  352. return
  353. }
  354. if options.resetDatabase {
  355. resetDB()
  356. return
  357. }
  358. // ---BEGIN TEMPORARY HACK---
  359. //
  360. // Remove once v0.14.21-v0.14.22 are rare enough. Those versions,
  361. // essentially:
  362. //
  363. // 1. os.Setenv("STMONITORED", "yes")
  364. // 2. os.Setenv("STNORESTART", "")
  365. //
  366. // where the intention was for 2 to cancel out 1 instead of setting
  367. // STNORESTART to the empty value. We check for exactly this combination
  368. // and pretend that neither was set. Looking through os.Environ lets us
  369. // distinguish. Luckily, we weren't smart enough to use os.Unsetenv.
  370. matches := 0
  371. for _, str := range os.Environ() {
  372. if str == "STNORESTART=" {
  373. matches++
  374. }
  375. if str == "STMONITORED=yes" {
  376. matches++
  377. }
  378. }
  379. if matches == 2 {
  380. innerProcess = false
  381. }
  382. // ---END TEMPORARY HACK---
  383. if innerProcess || options.noRestart {
  384. syncthingMain(options)
  385. } else {
  386. monitorMain(options)
  387. }
  388. }
  389. func openGUI() {
  390. cfg, _ := loadConfig()
  391. if cfg.GUI().Enabled {
  392. openURL(cfg.GUI().URL())
  393. } else {
  394. l.Warnln("Browser: GUI is currently disabled")
  395. }
  396. }
  397. func generate(generateDir string) {
  398. dir, err := osutil.ExpandTilde(generateDir)
  399. if err != nil {
  400. l.Fatalln("generate:", err)
  401. }
  402. ensureDir(dir, 0700)
  403. certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem")
  404. cert, err := tls.LoadX509KeyPair(certFile, keyFile)
  405. if err == nil {
  406. l.Warnln("Key exists; will not overwrite.")
  407. l.Infoln("Device ID:", protocol.NewDeviceID(cert.Certificate[0]))
  408. } else {
  409. cert, err = tlsutil.NewCertificate(certFile, keyFile, tlsDefaultCommonName, bepRSABits)
  410. if err != nil {
  411. l.Fatalln("Create certificate:", err)
  412. }
  413. myID = protocol.NewDeviceID(cert.Certificate[0])
  414. if err != nil {
  415. l.Fatalln("Load certificate:", err)
  416. }
  417. if err == nil {
  418. l.Infoln("Device ID:", protocol.NewDeviceID(cert.Certificate[0]))
  419. }
  420. }
  421. cfgFile := filepath.Join(dir, "config.xml")
  422. if _, err := os.Stat(cfgFile); err == nil {
  423. l.Warnln("Config exists; will not overwrite.")
  424. return
  425. }
  426. var myName, _ = os.Hostname()
  427. var newCfg = defaultConfig(myName)
  428. var cfg = config.Wrap(cfgFile, newCfg)
  429. err = cfg.Save()
  430. if err != nil {
  431. l.Warnln("Failed to save config", err)
  432. }
  433. }
  434. func debugFacilities() string {
  435. facilities := l.Facilities()
  436. // Get a sorted list of names
  437. var names []string
  438. maxLen := 0
  439. for name := range facilities {
  440. names = append(names, name)
  441. if len(name) > maxLen {
  442. maxLen = len(name)
  443. }
  444. }
  445. sort.Strings(names)
  446. // Format the choices
  447. b := new(bytes.Buffer)
  448. for _, name := range names {
  449. fmt.Fprintf(b, " %-*s - %s\n", maxLen, name, facilities[name])
  450. }
  451. return b.String()
  452. }
  453. func checkUpgrade() upgrade.Release {
  454. cfg, _ := loadConfig()
  455. opts := cfg.Options()
  456. release, err := upgrade.LatestRelease(opts.ReleasesURL, Version, opts.UpgradeToPreReleases)
  457. if err != nil {
  458. l.Fatalln("Upgrade:", err)
  459. }
  460. if upgrade.CompareVersions(release.Tag, Version) <= 0 {
  461. noUpgradeMessage := "No upgrade available (current %q >= latest %q)."
  462. l.Infof(noUpgradeMessage, Version, release.Tag)
  463. os.Exit(exitNoUpgradeAvailable)
  464. }
  465. l.Infof("Upgrade available (current %q < latest %q)", Version, release.Tag)
  466. return release
  467. }
  468. func performUpgrade(release upgrade.Release) {
  469. // Use leveldb database locks to protect against concurrent upgrades
  470. _, err := db.Open(locations[locDatabase])
  471. if err == nil {
  472. err = upgrade.To(release)
  473. if err != nil {
  474. l.Fatalln("Upgrade:", err)
  475. }
  476. l.Infof("Upgraded to %q", release.Tag)
  477. } else {
  478. l.Infoln("Attempting upgrade through running Syncthing...")
  479. err = upgradeViaRest()
  480. if err != nil {
  481. l.Fatalln("Upgrade:", err)
  482. }
  483. l.Infoln("Syncthing upgrading")
  484. os.Exit(exitUpgrading)
  485. }
  486. }
  487. func upgradeViaRest() error {
  488. cfg, _ := loadConfig()
  489. u, err := url.Parse(cfg.GUI().URL())
  490. if err != nil {
  491. return err
  492. }
  493. u.Path = path.Join(u.Path, "rest/system/upgrade")
  494. target := u.String()
  495. r, _ := http.NewRequest("POST", target, nil)
  496. r.Header.Set("X-API-Key", cfg.GUI().APIKey)
  497. tr := &http.Transport{
  498. Dial: dialer.Dial,
  499. Proxy: http.ProxyFromEnvironment,
  500. TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
  501. }
  502. client := &http.Client{
  503. Transport: tr,
  504. Timeout: 60 * time.Second,
  505. }
  506. resp, err := client.Do(r)
  507. if err != nil {
  508. return err
  509. }
  510. if resp.StatusCode != 200 {
  511. bs, err := ioutil.ReadAll(resp.Body)
  512. defer resp.Body.Close()
  513. if err != nil {
  514. return err
  515. }
  516. return errors.New(string(bs))
  517. }
  518. return err
  519. }
  520. func syncthingMain(runtimeOptions RuntimeOptions) {
  521. setupSignalHandling()
  522. // Create a main service manager. We'll add things to this as we go along.
  523. // We want any logging it does to go through our log system.
  524. mainService := suture.New("main", suture.Spec{
  525. Log: func(line string) {
  526. l.Debugln(line)
  527. },
  528. })
  529. mainService.ServeBackground()
  530. // Set a log prefix similar to the ID we will have later on, or early log
  531. // lines look ugly.
  532. l.SetPrefix("[start] ")
  533. if runtimeOptions.auditEnabled {
  534. startAuditing(mainService, runtimeOptions.auditFile)
  535. }
  536. if runtimeOptions.verbose {
  537. mainService.Add(newVerboseService())
  538. }
  539. errors := logger.NewRecorder(l, logger.LevelWarn, maxSystemErrors, 0)
  540. systemLog := logger.NewRecorder(l, logger.LevelDebug, maxSystemLog, initialSystemLog)
  541. // Event subscription for the API; must start early to catch the early
  542. // events. The LocalChangeDetected event might overwhelm the event
  543. // receiver in some situations so we will not subscribe to it here.
  544. apiSub := events.NewBufferedSubscription(events.Default.Subscribe(events.AllEvents&^events.LocalChangeDetected&^events.RemoteChangeDetected), 1000)
  545. diskSub := events.NewBufferedSubscription(events.Default.Subscribe(events.LocalChangeDetected|events.RemoteChangeDetected), 1000)
  546. if len(os.Getenv("GOMAXPROCS")) == 0 {
  547. runtime.GOMAXPROCS(runtime.NumCPU())
  548. }
  549. // Attempt to increase the limit on number of open files to the maximum
  550. // allowed, in case we have many peers. We don't really care enough to
  551. // report the error if there is one.
  552. osutil.MaximizeOpenFileLimit()
  553. // Ensure that we have a certificate and key.
  554. cert, err := tls.LoadX509KeyPair(locations[locCertFile], locations[locKeyFile])
  555. if err != nil {
  556. l.Infof("Generating ECDSA key and certificate for %s...", tlsDefaultCommonName)
  557. cert, err = tlsutil.NewCertificate(locations[locCertFile], locations[locKeyFile], tlsDefaultCommonName, bepRSABits)
  558. if err != nil {
  559. l.Fatalln(err)
  560. }
  561. }
  562. myID = protocol.NewDeviceID(cert.Certificate[0])
  563. l.SetPrefix(fmt.Sprintf("[%s] ", myID.String()[:5]))
  564. l.Infoln(LongVersion)
  565. l.Infoln("My ID:", myID)
  566. sha256.SelectAlgo()
  567. sha256.Report()
  568. perfWithWeakHash := cpuBench(3, 150*time.Millisecond, true)
  569. l.Infof("Hashing performance with weak hash is %.02f MB/s", perfWithWeakHash)
  570. perfWithoutWeakHash := cpuBench(3, 150*time.Millisecond, false)
  571. l.Infof("Hashing performance without weak hash is %.02f MB/s", perfWithoutWeakHash)
  572. // Emit the Starting event, now that we know who we are.
  573. events.Default.Log(events.Starting, map[string]string{
  574. "home": baseDirs["config"],
  575. "myID": myID.String(),
  576. })
  577. cfg := loadOrCreateConfig()
  578. if err := checkShortIDs(cfg); err != nil {
  579. l.Fatalln("Short device IDs are in conflict. Unlucky!\n Regenerate the device ID of one of the following:\n ", err)
  580. }
  581. if len(runtimeOptions.profiler) > 0 {
  582. go func() {
  583. l.Debugln("Starting profiler on", runtimeOptions.profiler)
  584. runtime.SetBlockProfileRate(1)
  585. err := http.ListenAndServe(runtimeOptions.profiler, nil)
  586. if err != nil {
  587. l.Fatalln(err)
  588. }
  589. }()
  590. }
  591. // The TLS configuration is used for both the listening socket and outgoing
  592. // connections.
  593. tlsCfg := &tls.Config{
  594. Certificates: []tls.Certificate{cert},
  595. NextProtos: []string{bepProtocolName},
  596. ClientAuth: tls.RequestClientCert,
  597. SessionTicketsDisabled: true,
  598. InsecureSkipVerify: true,
  599. MinVersion: tls.VersionTLS12,
  600. CipherSuites: []uint16{
  601. 0xCCA8, // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, Go 1.8
  602. 0xCCA9, // TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, Go 1.8
  603. tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
  604. tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
  605. tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
  606. tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
  607. tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
  608. tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
  609. tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
  610. tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
  611. },
  612. }
  613. opts := cfg.Options()
  614. if opts.WeakHashSelectionMethod == config.WeakHashAuto {
  615. if perfWithoutWeakHash*0.8 > perfWithWeakHash {
  616. l.Infof("Weak hash disabled, as it has an unacceptable performance impact.")
  617. weakhash.Enabled = false
  618. } else {
  619. l.Infof("Weak hash enabled, as it has an acceptable performance impact.")
  620. weakhash.Enabled = true
  621. }
  622. } else if opts.WeakHashSelectionMethod == config.WeakHashNever {
  623. l.Infof("Disabling weak hash")
  624. weakhash.Enabled = false
  625. } else if opts.WeakHashSelectionMethod == config.WeakHashAlways {
  626. l.Infof("Enabling weak hash")
  627. weakhash.Enabled = true
  628. }
  629. if (opts.MaxRecvKbps > 0 || opts.MaxSendKbps > 0) && !opts.LimitBandwidthInLan {
  630. lans, _ = osutil.GetLans()
  631. for _, lan := range opts.AlwaysLocalNets {
  632. _, ipnet, err := net.ParseCIDR(lan)
  633. if err != nil {
  634. l.Infoln("Network", lan, "is malformed:", err)
  635. continue
  636. }
  637. lans = append(lans, ipnet)
  638. }
  639. networks := make([]string, len(lans))
  640. for i, lan := range lans {
  641. networks[i] = lan.String()
  642. }
  643. l.Infoln("Local networks:", strings.Join(networks, ", "))
  644. }
  645. dbFile := locations[locDatabase]
  646. ldb, err := db.Open(dbFile)
  647. if err != nil {
  648. l.Fatalln("Cannot open database:", err, "- Is another copy of Syncthing already running?")
  649. }
  650. if runtimeOptions.resetDeltaIdxs {
  651. l.Infoln("Reinitializing delta index IDs")
  652. ldb.DropDeltaIndexIDs()
  653. }
  654. protectedFiles := []string{
  655. locations[locDatabase],
  656. locations[locConfigFile],
  657. locations[locCertFile],
  658. locations[locKeyFile],
  659. }
  660. // Remove database entries for folders that no longer exist in the config
  661. folders := cfg.Folders()
  662. for _, folder := range ldb.ListFolders() {
  663. if _, ok := folders[folder]; !ok {
  664. l.Infof("Cleaning data for dropped folder %q", folder)
  665. db.DropFolder(ldb, folder)
  666. }
  667. }
  668. if cfg.RawCopy().OriginalVersion == 15 {
  669. // The config version 15->16 migration is about handling ignores and
  670. // delta indexes and requires that we drop existing indexes that
  671. // have been incorrectly ignore filtered.
  672. ldb.DropDeltaIndexIDs()
  673. }
  674. if cfg.RawCopy().OriginalVersion < 19 {
  675. // Converts old symlink types to new in the entire database.
  676. ldb.ConvertSymlinkTypes()
  677. }
  678. m := model.NewModel(cfg, myID, myDeviceName(cfg), "syncthing", Version, ldb, protectedFiles)
  679. if t := os.Getenv("STDEADLOCKTIMEOUT"); len(t) > 0 {
  680. it, err := strconv.Atoi(t)
  681. if err == nil {
  682. m.StartDeadlockDetector(time.Duration(it) * time.Second)
  683. }
  684. } else if !IsRelease || IsBeta {
  685. m.StartDeadlockDetector(20 * time.Minute)
  686. }
  687. if runtimeOptions.unpaused {
  688. setPauseState(cfg, false)
  689. } else if runtimeOptions.paused {
  690. setPauseState(cfg, true)
  691. }
  692. // Add and start folders
  693. for _, folderCfg := range cfg.Folders() {
  694. if folderCfg.Paused {
  695. continue
  696. }
  697. m.AddFolder(folderCfg)
  698. m.StartFolder(folderCfg.ID)
  699. }
  700. mainService.Add(m)
  701. // Start discovery
  702. cachedDiscovery := discover.NewCachingMux()
  703. mainService.Add(cachedDiscovery)
  704. // Start connection management
  705. connectionsService := connections.NewService(cfg, myID, m, tlsCfg, cachedDiscovery, bepProtocolName, tlsDefaultCommonName, lans)
  706. mainService.Add(connectionsService)
  707. if cfg.Options().GlobalAnnEnabled {
  708. for _, srv := range cfg.GlobalDiscoveryServers() {
  709. l.Infoln("Using discovery server", srv)
  710. gd, err := discover.NewGlobal(srv, cert, connectionsService)
  711. if err != nil {
  712. l.Warnln("Global discovery:", err)
  713. continue
  714. }
  715. // Each global discovery server gets its results cached for five
  716. // minutes, and is not asked again for a minute when it's returned
  717. // unsuccessfully.
  718. cachedDiscovery.Add(gd, 5*time.Minute, time.Minute, globalDiscoveryPriority)
  719. }
  720. }
  721. if cfg.Options().LocalAnnEnabled {
  722. // v4 broadcasts
  723. bcd, err := discover.NewLocal(myID, fmt.Sprintf(":%d", cfg.Options().LocalAnnPort), connectionsService)
  724. if err != nil {
  725. l.Warnln("IPv4 local discovery:", err)
  726. } else {
  727. cachedDiscovery.Add(bcd, 0, 0, ipv4LocalDiscoveryPriority)
  728. }
  729. // v6 multicasts
  730. mcd, err := discover.NewLocal(myID, cfg.Options().LocalAnnMCAddr, connectionsService)
  731. if err != nil {
  732. l.Warnln("IPv6 local discovery:", err)
  733. } else {
  734. cachedDiscovery.Add(mcd, 0, 0, ipv6LocalDiscoveryPriority)
  735. }
  736. }
  737. // GUI
  738. setupGUI(mainService, cfg, m, apiSub, diskSub, cachedDiscovery, connectionsService, errors, systemLog, runtimeOptions)
  739. if runtimeOptions.cpuProfile {
  740. f, err := os.Create(fmt.Sprintf("cpu-%d.pprof", os.Getpid()))
  741. if err != nil {
  742. log.Fatal(err)
  743. }
  744. pprof.StartCPUProfile(f)
  745. }
  746. for _, device := range cfg.Devices() {
  747. if len(device.Name) > 0 {
  748. l.Infof("Device %s is %q at %v", device.DeviceID, device.Name, device.Addresses)
  749. }
  750. }
  751. // Candidate builds always run with usage reporting.
  752. if IsCandidate {
  753. l.Infoln("Anonymous usage reporting is always enabled for candidate releases.")
  754. opts.URAccepted = usageReportVersion
  755. // Unique ID will be set and config saved below if necessary.
  756. }
  757. if opts.URAccepted > 0 && opts.URAccepted < usageReportVersion {
  758. l.Infoln("Anonymous usage report has changed; revoking acceptance")
  759. opts.URAccepted = 0
  760. opts.URUniqueID = ""
  761. cfg.SetOptions(opts)
  762. }
  763. if opts.URAccepted >= usageReportVersion && opts.URUniqueID == "" {
  764. // Generate and save a new unique ID if it is missing.
  765. opts.URUniqueID = rand.String(8)
  766. cfg.SetOptions(opts)
  767. cfg.Save()
  768. }
  769. // The usageReportingManager registers itself to listen to configuration
  770. // changes, and there's nothing more we need to tell it from the outside.
  771. // Hence we don't keep the returned pointer.
  772. newUsageReportingManager(cfg, m)
  773. if opts.RestartOnWakeup {
  774. go standbyMonitor()
  775. }
  776. // Candidate builds should auto upgrade. Make sure the option is set,
  777. // unless we are in a build where it's disabled or the STNOUPGRADE
  778. // environment variable is set.
  779. if IsCandidate && !upgrade.DisabledByCompilation && !noUpgradeFromEnv {
  780. l.Infoln("Automatic upgrade is always enabled for candidate releases.")
  781. if opts.AutoUpgradeIntervalH == 0 || opts.AutoUpgradeIntervalH > 24 {
  782. opts.AutoUpgradeIntervalH = 12
  783. // Set the option into the config as well, as the auto upgrade
  784. // loop expects to read a valid interval from there.
  785. cfg.SetOptions(opts)
  786. cfg.Save()
  787. }
  788. // We don't tweak the user's choice of upgrading to pre-releases or
  789. // not, as otherwise they cannot step off the candidate channel.
  790. }
  791. if opts.AutoUpgradeIntervalH > 0 {
  792. if noUpgradeFromEnv {
  793. l.Infof("No automatic upgrades; STNOUPGRADE environment variable defined.")
  794. } else {
  795. go autoUpgrade(cfg)
  796. }
  797. }
  798. events.Default.Log(events.StartupComplete, map[string]string{
  799. "myID": myID.String(),
  800. })
  801. cleanConfigDirectory()
  802. code := <-stop
  803. mainService.Stop()
  804. l.Infoln("Exiting")
  805. if runtimeOptions.cpuProfile {
  806. pprof.StopCPUProfile()
  807. }
  808. os.Exit(code)
  809. }
  810. func myDeviceName(cfg *config.Wrapper) string {
  811. devices := cfg.Devices()
  812. myName := devices[myID].Name
  813. if myName == "" {
  814. myName, _ = os.Hostname()
  815. }
  816. return myName
  817. }
  818. func setupSignalHandling() {
  819. // Exit cleanly with "restarting" code on SIGHUP.
  820. restartSign := make(chan os.Signal, 1)
  821. sigHup := syscall.Signal(1)
  822. signal.Notify(restartSign, sigHup)
  823. go func() {
  824. <-restartSign
  825. stop <- exitRestarting
  826. }()
  827. // Exit with "success" code (no restart) on INT/TERM
  828. stopSign := make(chan os.Signal, 1)
  829. sigTerm := syscall.Signal(15)
  830. signal.Notify(stopSign, os.Interrupt, sigTerm)
  831. go func() {
  832. <-stopSign
  833. stop <- exitSuccess
  834. }()
  835. }
  836. func loadConfig() (*config.Wrapper, error) {
  837. cfgFile := locations[locConfigFile]
  838. cfg, err := config.Load(cfgFile, myID)
  839. if err != nil {
  840. myName, _ := os.Hostname()
  841. newCfg := defaultConfig(myName)
  842. cfg = config.Wrap(cfgFile, newCfg)
  843. }
  844. return cfg, err
  845. }
  846. func loadOrCreateConfig() *config.Wrapper {
  847. cfg, err := loadConfig()
  848. if os.IsNotExist(err) {
  849. cfg.Save()
  850. l.Infof("Defaults saved. Edit %s to taste or use the GUI\n", cfg.ConfigPath())
  851. } else if err != nil {
  852. l.Fatalln("Config:", err)
  853. }
  854. if cfg.RawCopy().OriginalVersion != config.CurrentVersion {
  855. err = archiveAndSaveConfig(cfg)
  856. if err != nil {
  857. l.Fatalln("Config archive:", err)
  858. }
  859. }
  860. return cfg
  861. }
  862. func archiveAndSaveConfig(cfg *config.Wrapper) error {
  863. // Copy the existing config to an archive copy
  864. archivePath := cfg.ConfigPath() + fmt.Sprintf(".v%d", cfg.RawCopy().OriginalVersion)
  865. l.Infoln("Archiving a copy of old config file format at:", archivePath)
  866. if err := copyFile(cfg.ConfigPath(), archivePath); err != nil {
  867. return err
  868. }
  869. // Do a regular atomic config sve
  870. return cfg.Save()
  871. }
  872. func copyFile(src, dst string) error {
  873. bs, err := ioutil.ReadFile(src)
  874. if err != nil {
  875. return err
  876. }
  877. if err := ioutil.WriteFile(dst, bs, 0600); err != nil {
  878. // Attempt to clean up
  879. os.Remove(dst)
  880. return err
  881. }
  882. return nil
  883. }
  884. func startAuditing(mainService *suture.Supervisor, auditFile string) {
  885. var fd io.Writer
  886. var err error
  887. var auditDest string
  888. var auditFlags int
  889. if auditFile == "-" {
  890. fd = os.Stdout
  891. auditDest = "stdout"
  892. } else if auditFile == "--" {
  893. fd = os.Stderr
  894. auditDest = "stderr"
  895. } else {
  896. if auditFile == "" {
  897. auditFile = timestampedLoc(locAuditLog)
  898. auditFlags = os.O_WRONLY | os.O_CREATE | os.O_EXCL
  899. } else {
  900. auditFlags = os.O_WRONLY | os.O_CREATE | os.O_APPEND
  901. }
  902. fd, err = os.OpenFile(auditFile, auditFlags, 0600)
  903. if err != nil {
  904. l.Fatalln("Audit:", err)
  905. }
  906. auditDest = auditFile
  907. }
  908. auditService := newAuditService(fd)
  909. mainService.Add(auditService)
  910. // We wait for the audit service to fully start before we return, to
  911. // ensure we capture all events from the start.
  912. auditService.WaitForStart()
  913. l.Infoln("Audit log in", auditDest)
  914. }
  915. func setupGUI(mainService *suture.Supervisor, cfg *config.Wrapper, m *model.Model, apiSub events.BufferedSubscription, diskSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService *connections.Service, errors, systemLog logger.Recorder, runtimeOptions RuntimeOptions) {
  916. guiCfg := cfg.GUI()
  917. if !guiCfg.Enabled {
  918. return
  919. }
  920. if guiCfg.InsecureAdminAccess {
  921. l.Warnln("Insecure admin access is enabled.")
  922. }
  923. api := newAPIService(myID, cfg, locations[locHTTPSCertFile], locations[locHTTPSKeyFile], runtimeOptions.assetDir, m, apiSub, diskSub, discoverer, connectionsService, errors, systemLog)
  924. cfg.Subscribe(api)
  925. mainService.Add(api)
  926. if cfg.Options().StartBrowser && !runtimeOptions.noBrowser && !runtimeOptions.stRestarting {
  927. // Can potentially block if the utility we are invoking doesn't
  928. // fork, and just execs, hence keep it in it's own routine.
  929. <-api.startedOnce
  930. go openURL(guiCfg.URL())
  931. }
  932. }
  933. func defaultConfig(myName string) config.Configuration {
  934. var defaultFolder config.FolderConfiguration
  935. if !noDefaultFolder {
  936. l.Infoln("Default folder created and/or linked to new config")
  937. defaultFolder = config.NewFolderConfiguration("default", locations[locDefFolder])
  938. defaultFolder.Label = "Default Folder"
  939. defaultFolder.RescanIntervalS = 60
  940. defaultFolder.MinDiskFreePct = 1
  941. defaultFolder.Devices = []config.FolderDeviceConfiguration{{DeviceID: myID}}
  942. defaultFolder.AutoNormalize = true
  943. defaultFolder.MaxConflicts = -1
  944. } else {
  945. l.Infoln("We will skip creation of a default folder on first start since the proper envvar is set")
  946. }
  947. thisDevice := config.NewDeviceConfiguration(myID, myName)
  948. thisDevice.Addresses = []string{"dynamic"}
  949. newCfg := config.New(myID)
  950. if !noDefaultFolder {
  951. newCfg.Folders = []config.FolderConfiguration{defaultFolder}
  952. }
  953. newCfg.Devices = []config.DeviceConfiguration{thisDevice}
  954. port, err := getFreePort("127.0.0.1", 8384)
  955. if err != nil {
  956. l.Fatalln("get free port (GUI):", err)
  957. }
  958. newCfg.GUI.RawAddress = fmt.Sprintf("127.0.0.1:%d", port)
  959. port, err = getFreePort("0.0.0.0", 22000)
  960. if err != nil {
  961. l.Fatalln("get free port (BEP):", err)
  962. }
  963. if port == 22000 {
  964. newCfg.Options.ListenAddresses = []string{"default"}
  965. } else {
  966. newCfg.Options.ListenAddresses = []string{
  967. fmt.Sprintf("tcp://%s", net.JoinHostPort("0.0.0.0", strconv.Itoa(port))),
  968. "dynamic+https://relays.syncthing.net/endpoint",
  969. }
  970. }
  971. return newCfg
  972. }
  973. func resetDB() error {
  974. return os.RemoveAll(locations[locDatabase])
  975. }
  976. func restart() {
  977. l.Infoln("Restarting")
  978. stop <- exitRestarting
  979. }
  980. func shutdown() {
  981. l.Infoln("Shutting down")
  982. stop <- exitSuccess
  983. }
  984. func ensureDir(dir string, mode os.FileMode) {
  985. err := osutil.MkdirAll(dir, mode)
  986. if err != nil {
  987. l.Fatalln(err)
  988. }
  989. if fi, err := os.Stat(dir); err == nil {
  990. // Apprently the stat may fail even though the mkdirall passed. If it
  991. // does, we'll just assume things are in order and let other things
  992. // fail (like loading or creating the config...).
  993. currentMode := fi.Mode() & 0777
  994. if currentMode != mode {
  995. err := os.Chmod(dir, mode)
  996. // This can fail on crappy filesystems, nothing we can do about it.
  997. if err != nil {
  998. l.Warnln(err)
  999. }
  1000. }
  1001. }
  1002. }
  1003. // getFreePort returns a free TCP port fort listening on. The ports given are
  1004. // tried in succession and the first to succeed is returned. If none succeed,
  1005. // a random high port is returned.
  1006. func getFreePort(host string, ports ...int) (int, error) {
  1007. for _, port := range ports {
  1008. c, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port))
  1009. if err == nil {
  1010. c.Close()
  1011. return port, nil
  1012. }
  1013. }
  1014. c, err := net.Listen("tcp", host+":0")
  1015. if err != nil {
  1016. return 0, err
  1017. }
  1018. addr := c.Addr().(*net.TCPAddr)
  1019. c.Close()
  1020. return addr.Port, nil
  1021. }
  1022. func standbyMonitor() {
  1023. restartDelay := 60 * time.Second
  1024. now := time.Now()
  1025. for {
  1026. time.Sleep(10 * time.Second)
  1027. if time.Since(now) > 2*time.Minute {
  1028. l.Infof("Paused state detected, possibly woke up from standby. Restarting in %v.", restartDelay)
  1029. // We most likely just woke from standby. If we restart
  1030. // immediately chances are we won't have networking ready. Give
  1031. // things a moment to stabilize.
  1032. time.Sleep(restartDelay)
  1033. restart()
  1034. return
  1035. }
  1036. now = time.Now()
  1037. }
  1038. }
  1039. func autoUpgrade(cfg *config.Wrapper) {
  1040. timer := time.NewTimer(0)
  1041. sub := events.Default.Subscribe(events.DeviceConnected)
  1042. for {
  1043. select {
  1044. case event := <-sub.C():
  1045. data, ok := event.Data.(map[string]string)
  1046. if !ok || data["clientName"] != "syncthing" || upgrade.CompareVersions(data["clientVersion"], Version) != upgrade.Newer {
  1047. continue
  1048. }
  1049. l.Infof("Connected to device %s with a newer version (current %q < remote %q). Checking for upgrades.", data["id"], Version, data["clientVersion"])
  1050. case <-timer.C:
  1051. }
  1052. opts := cfg.Options()
  1053. checkInterval := time.Duration(opts.AutoUpgradeIntervalH) * time.Hour
  1054. if checkInterval < time.Hour {
  1055. // We shouldn't be here if AutoUpgradeIntervalH < 1, but for
  1056. // safety's sake.
  1057. checkInterval = time.Hour
  1058. }
  1059. rel, err := upgrade.LatestRelease(opts.ReleasesURL, Version, opts.UpgradeToPreReleases)
  1060. if err == upgrade.ErrUpgradeUnsupported {
  1061. events.Default.Unsubscribe(sub)
  1062. return
  1063. }
  1064. if err != nil {
  1065. // Don't complain too loudly here; we might simply not have
  1066. // internet connectivity, or the upgrade server might be down.
  1067. l.Infoln("Automatic upgrade:", err)
  1068. timer.Reset(checkInterval)
  1069. continue
  1070. }
  1071. if upgrade.CompareVersions(rel.Tag, Version) != upgrade.Newer {
  1072. // Skip equal, older or majorly newer (incompatible) versions
  1073. timer.Reset(checkInterval)
  1074. continue
  1075. }
  1076. l.Infof("Automatic upgrade (current %q < latest %q)", Version, rel.Tag)
  1077. err = upgrade.To(rel)
  1078. if err != nil {
  1079. l.Warnln("Automatic upgrade:", err)
  1080. timer.Reset(checkInterval)
  1081. continue
  1082. }
  1083. events.Default.Unsubscribe(sub)
  1084. l.Warnf("Automatically upgraded to version %q. Restarting in 1 minute.", rel.Tag)
  1085. time.Sleep(time.Minute)
  1086. stop <- exitUpgrading
  1087. return
  1088. }
  1089. }
  1090. // cleanConfigDirectory removes old, unused configuration and index formats, a
  1091. // suitable time after they have gone out of fashion.
  1092. func cleanConfigDirectory() {
  1093. patterns := map[string]time.Duration{
  1094. "panic-*.log": 7 * 24 * time.Hour, // keep panic logs for a week
  1095. "audit-*.log": 7 * 24 * time.Hour, // keep audit logs for a week
  1096. "index": 14 * 24 * time.Hour, // keep old index format for two weeks
  1097. "index-v0.11.0.db": 14 * 24 * time.Hour, // keep old index format for two weeks
  1098. "index-v0.13.0.db": 14 * 24 * time.Hour, // keep old index format for two weeks
  1099. "index*.converted": 14 * 24 * time.Hour, // keep old converted indexes for two weeks
  1100. "config.xml.v*": 30 * 24 * time.Hour, // old config versions for a month
  1101. "*.idx.gz": 30 * 24 * time.Hour, // these should for sure no longer exist
  1102. "backup-of-v0.8": 30 * 24 * time.Hour, // these neither
  1103. "tmp-index-sorter.*": time.Minute, // these should never exist on startup
  1104. }
  1105. for pat, dur := range patterns {
  1106. pat = filepath.Join(baseDirs["config"], pat)
  1107. files, err := osutil.Glob(pat)
  1108. if err != nil {
  1109. l.Infoln("Cleaning:", err)
  1110. continue
  1111. }
  1112. for _, file := range files {
  1113. info, err := osutil.Lstat(file)
  1114. if err != nil {
  1115. l.Infoln("Cleaning:", err)
  1116. continue
  1117. }
  1118. if time.Since(info.ModTime()) > dur {
  1119. if err = os.RemoveAll(file); err != nil {
  1120. l.Infoln("Cleaning:", err)
  1121. } else {
  1122. l.Infoln("Cleaned away old file", filepath.Base(file))
  1123. }
  1124. }
  1125. }
  1126. }
  1127. }
  1128. // checkShortIDs verifies that the configuration won't result in duplicate
  1129. // short ID:s; that is, that the devices in the cluster all have unique
  1130. // initial 64 bits.
  1131. func checkShortIDs(cfg *config.Wrapper) error {
  1132. exists := make(map[protocol.ShortID]protocol.DeviceID)
  1133. for deviceID := range cfg.Devices() {
  1134. shortID := deviceID.Short()
  1135. if otherID, ok := exists[shortID]; ok {
  1136. return fmt.Errorf("%v in conflict with %v", deviceID, otherID)
  1137. }
  1138. exists[shortID] = deviceID
  1139. }
  1140. return nil
  1141. }
  1142. func showPaths() {
  1143. fmt.Printf("Configuration file:\n\t%s\n\n", locations[locConfigFile])
  1144. fmt.Printf("Database directory:\n\t%s\n\n", locations[locDatabase])
  1145. fmt.Printf("Device private key & certificate files:\n\t%s\n\t%s\n\n", locations[locKeyFile], locations[locCertFile])
  1146. fmt.Printf("HTTPS private key & certificate files:\n\t%s\n\t%s\n\n", locations[locHTTPSKeyFile], locations[locHTTPSCertFile])
  1147. fmt.Printf("Log file:\n\t%s\n\n", locations[locLogFile])
  1148. fmt.Printf("GUI override directory:\n\t%s\n\n", locations[locGUIAssets])
  1149. fmt.Printf("Default sync folder directory:\n\t%s\n\n", locations[locDefFolder])
  1150. }
  1151. func setPauseState(cfg *config.Wrapper, paused bool) {
  1152. raw := cfg.RawCopy()
  1153. for i := range raw.Devices {
  1154. raw.Devices[i].Paused = paused
  1155. }
  1156. for i := range raw.Folders {
  1157. raw.Folders[i].Paused = paused
  1158. }
  1159. if err := cfg.Replace(raw); err != nil {
  1160. l.Fatalln("Cannot adjust paused state:", err)
  1161. }
  1162. }