main.go 38 KB

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