hostinfo_linux.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build linux,!android
  5. package controlclient
  6. import (
  7. "bytes"
  8. "fmt"
  9. "io/ioutil"
  10. "strings"
  11. "syscall"
  12. "tailscale.com/hostinfo"
  13. "tailscale.com/util/lineread"
  14. "tailscale.com/version/distro"
  15. )
  16. func init() {
  17. osVersion = osVersionLinux
  18. }
  19. func osVersionLinux() string {
  20. dist := distro.Get()
  21. propFile := "/etc/os-release"
  22. switch dist {
  23. case distro.Synology:
  24. propFile = "/etc.defaults/VERSION"
  25. case distro.OpenWrt:
  26. propFile = "/etc/openwrt_release"
  27. }
  28. m := map[string]string{}
  29. lineread.File(propFile, func(line []byte) error {
  30. eq := bytes.IndexByte(line, '=')
  31. if eq == -1 {
  32. return nil
  33. }
  34. k, v := string(line[:eq]), strings.Trim(string(line[eq+1:]), `"'`)
  35. m[k] = v
  36. return nil
  37. })
  38. var un syscall.Utsname
  39. syscall.Uname(&un)
  40. var attrBuf strings.Builder
  41. attrBuf.WriteString("; kernel=")
  42. for _, b := range un.Release {
  43. if b == 0 {
  44. break
  45. }
  46. attrBuf.WriteByte(byte(b))
  47. }
  48. if hostinfo.InContainer() {
  49. attrBuf.WriteString("; container")
  50. }
  51. if env := hostinfo.GetEnvType(); env != "" {
  52. fmt.Fprintf(&attrBuf, "; env=%s", env)
  53. }
  54. attr := attrBuf.String()
  55. id := m["ID"]
  56. switch id {
  57. case "debian":
  58. slurp, _ := ioutil.ReadFile("/etc/debian_version")
  59. return fmt.Sprintf("Debian %s (%s)%s", bytes.TrimSpace(slurp), m["VERSION_CODENAME"], attr)
  60. case "ubuntu":
  61. return fmt.Sprintf("Ubuntu %s%s", m["VERSION"], attr)
  62. case "", "centos": // CentOS 6 has no /etc/os-release, so its id is ""
  63. if cr, _ := ioutil.ReadFile("/etc/centos-release"); len(cr) > 0 { // "CentOS release 6.10 (Final)
  64. return fmt.Sprintf("%s%s", bytes.TrimSpace(cr), attr)
  65. }
  66. fallthrough
  67. case "fedora", "rhel", "alpine", "nixos":
  68. // Their PRETTY_NAME is fine as-is for all versions I tested.
  69. fallthrough
  70. default:
  71. if v := m["PRETTY_NAME"]; v != "" {
  72. return fmt.Sprintf("%s%s", v, attr)
  73. }
  74. }
  75. switch dist {
  76. case distro.Synology:
  77. return fmt.Sprintf("Synology %s%s", m["productversion"], attr)
  78. case distro.OpenWrt:
  79. return fmt.Sprintf("OpenWrt %s%s", m["DISTRIB_RELEASE"], attr)
  80. }
  81. return fmt.Sprintf("Other%s", attr)
  82. }