main.go 38 KB

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