| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- // Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // +build linux,!android
- package controlclient
- import (
- "bytes"
- "fmt"
- "io/ioutil"
- "strings"
- "syscall"
- "tailscale.com/hostinfo"
- "tailscale.com/util/lineread"
- "tailscale.com/version/distro"
- )
- func init() {
- osVersion = osVersionLinux
- }
- func osVersionLinux() string {
- dist := distro.Get()
- propFile := "/etc/os-release"
- switch dist {
- case distro.Synology:
- propFile = "/etc.defaults/VERSION"
- case distro.OpenWrt:
- propFile = "/etc/openwrt_release"
- }
- m := map[string]string{}
- lineread.File(propFile, func(line []byte) error {
- eq := bytes.IndexByte(line, '=')
- if eq == -1 {
- return nil
- }
- k, v := string(line[:eq]), strings.Trim(string(line[eq+1:]), `"'`)
- m[k] = v
- return nil
- })
- var un syscall.Utsname
- syscall.Uname(&un)
- var attrBuf strings.Builder
- attrBuf.WriteString("; kernel=")
- for _, b := range un.Release {
- if b == 0 {
- break
- }
- attrBuf.WriteByte(byte(b))
- }
- if hostinfo.InContainer() {
- attrBuf.WriteString("; container")
- }
- if env := hostinfo.GetEnvType(); env != "" {
- fmt.Fprintf(&attrBuf, "; env=%s", env)
- }
- attr := attrBuf.String()
- id := m["ID"]
- switch id {
- case "debian":
- slurp, _ := ioutil.ReadFile("/etc/debian_version")
- return fmt.Sprintf("Debian %s (%s)%s", bytes.TrimSpace(slurp), m["VERSION_CODENAME"], attr)
- case "ubuntu":
- return fmt.Sprintf("Ubuntu %s%s", m["VERSION"], attr)
- case "", "centos": // CentOS 6 has no /etc/os-release, so its id is ""
- if cr, _ := ioutil.ReadFile("/etc/centos-release"); len(cr) > 0 { // "CentOS release 6.10 (Final)
- return fmt.Sprintf("%s%s", bytes.TrimSpace(cr), attr)
- }
- fallthrough
- case "fedora", "rhel", "alpine", "nixos":
- // Their PRETTY_NAME is fine as-is for all versions I tested.
- fallthrough
- default:
- if v := m["PRETTY_NAME"]; v != "" {
- return fmt.Sprintf("%s%s", v, attr)
- }
- }
- switch dist {
- case distro.Synology:
- return fmt.Sprintf("Synology %s%s", m["productversion"], attr)
- case distro.OpenWrt:
- return fmt.Sprintf("OpenWrt %s%s", m["DISTRIB_RELEASE"], attr)
- }
- return fmt.Sprintf("Other%s", attr)
- }
|