|
@@ -9,7 +9,6 @@ package hostinfo
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
"bytes"
|
|
"bytes"
|
|
|
- "fmt"
|
|
|
|
|
"io/ioutil"
|
|
"io/ioutil"
|
|
|
"os"
|
|
"os"
|
|
|
"strings"
|
|
"strings"
|
|
@@ -21,14 +20,39 @@ import (
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
func init() {
|
|
|
- osVersion = osVersionLinux
|
|
|
|
|
|
|
+ osVersion = lazyOSVersion.Get
|
|
|
packageType = packageTypeLinux
|
|
packageType = packageTypeLinux
|
|
|
-
|
|
|
|
|
|
|
+ distroName = distroNameLinux
|
|
|
|
|
+ distroVersion = distroVersionLinux
|
|
|
|
|
+ distroCodeName = distroCodeNameLinux
|
|
|
if v := linuxDeviceModel(); v != "" {
|
|
if v := linuxDeviceModel(); v != "" {
|
|
|
SetDeviceModel(v)
|
|
SetDeviceModel(v)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+var (
|
|
|
|
|
+ lazyVersionMeta = &lazyAtomicValue[versionMeta]{f: ptrTo(linuxVersionMeta)}
|
|
|
|
|
+ lazyOSVersion = &lazyAtomicValue[string]{f: ptrTo(osVersionLinux)}
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+type versionMeta struct {
|
|
|
|
|
+ DistroName string
|
|
|
|
|
+ DistroVersion string
|
|
|
|
|
+ DistroCodeName string // "jammy", etc (VERSION_CODENAME from /etc/os-release)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func distroNameLinux() string {
|
|
|
|
|
+ return lazyVersionMeta.Get().DistroName
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func distroVersionLinux() string {
|
|
|
|
|
+ return lazyVersionMeta.Get().DistroVersion
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func distroCodeNameLinux() string {
|
|
|
|
|
+ return lazyVersionMeta.Get().DistroCodeName
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func linuxDeviceModel() string {
|
|
func linuxDeviceModel() string {
|
|
|
for _, path := range []string{
|
|
for _, path := range []string{
|
|
|
// First try the Synology-specific location.
|
|
// First try the Synology-specific location.
|
|
@@ -52,15 +76,22 @@ func linuxDeviceModel() string {
|
|
|
func getQnapQtsVersion(versionInfo string) string {
|
|
func getQnapQtsVersion(versionInfo string) string {
|
|
|
for _, field := range strings.Fields(versionInfo) {
|
|
for _, field := range strings.Fields(versionInfo) {
|
|
|
if suffix, ok := strs.CutPrefix(field, "QTSFW_"); ok {
|
|
if suffix, ok := strs.CutPrefix(field, "QTSFW_"); ok {
|
|
|
- return "QTS " + suffix
|
|
|
|
|
|
|
+ return suffix
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
return ""
|
|
return ""
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func osVersionLinux() string {
|
|
func osVersionLinux() string {
|
|
|
- // TODO(bradfitz,dgentry): cache this, or make caller(s) cache it.
|
|
|
|
|
|
|
+ var un unix.Utsname
|
|
|
|
|
+ unix.Uname(&un)
|
|
|
|
|
+ return unix.ByteSliceToString(un.Release[:])
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func linuxVersionMeta() (meta versionMeta) {
|
|
|
dist := distro.Get()
|
|
dist := distro.Get()
|
|
|
|
|
+ meta.DistroName = string(dist)
|
|
|
|
|
+
|
|
|
propFile := "/etc/os-release"
|
|
propFile := "/etc/os-release"
|
|
|
switch dist {
|
|
switch dist {
|
|
|
case distro.Synology:
|
|
case distro.Synology:
|
|
@@ -69,10 +100,12 @@ func osVersionLinux() string {
|
|
|
propFile = "/etc/openwrt_release"
|
|
propFile = "/etc/openwrt_release"
|
|
|
case distro.WDMyCloud:
|
|
case distro.WDMyCloud:
|
|
|
slurp, _ := ioutil.ReadFile("/etc/version")
|
|
slurp, _ := ioutil.ReadFile("/etc/version")
|
|
|
- return fmt.Sprintf("%s", string(bytes.TrimSpace(slurp)))
|
|
|
|
|
|
|
+ meta.DistroVersion = string(bytes.TrimSpace(slurp))
|
|
|
|
|
+ return
|
|
|
case distro.QNAP:
|
|
case distro.QNAP:
|
|
|
slurp, _ := ioutil.ReadFile("/etc/version_info")
|
|
slurp, _ := ioutil.ReadFile("/etc/version_info")
|
|
|
- return getQnapQtsVersion(string(slurp))
|
|
|
|
|
|
|
+ meta.DistroVersion = getQnapQtsVersion(string(slurp))
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
m := map[string]string{}
|
|
m := map[string]string{}
|
|
@@ -86,50 +119,45 @@ func osVersionLinux() string {
|
|
|
return nil
|
|
return nil
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
- var un unix.Utsname
|
|
|
|
|
- unix.Uname(&un)
|
|
|
|
|
-
|
|
|
|
|
- var attrBuf strings.Builder
|
|
|
|
|
- attrBuf.WriteString("; kernel=")
|
|
|
|
|
- attrBuf.WriteString(unix.ByteSliceToString(un.Release[:]))
|
|
|
|
|
- if inContainer() {
|
|
|
|
|
- attrBuf.WriteString("; container")
|
|
|
|
|
|
|
+ if v := m["VERSION_CODENAME"]; v != "" {
|
|
|
|
|
+ meta.DistroCodeName = v
|
|
|
}
|
|
}
|
|
|
- if env := GetEnvType(); env != "" {
|
|
|
|
|
- fmt.Fprintf(&attrBuf, "; env=%s", env)
|
|
|
|
|
|
|
+ if v := m["VERSION_ID"]; v != "" {
|
|
|
|
|
+ meta.DistroVersion = v
|
|
|
}
|
|
}
|
|
|
- attr := attrBuf.String()
|
|
|
|
|
-
|
|
|
|
|
id := m["ID"]
|
|
id := m["ID"]
|
|
|
-
|
|
|
|
|
|
|
+ if id != "" {
|
|
|
|
|
+ meta.DistroName = id
|
|
|
|
|
+ }
|
|
|
switch id {
|
|
switch id {
|
|
|
case "debian":
|
|
case "debian":
|
|
|
|
|
+ // Debian's VERSION_ID is just like "11". But /etc/debian_version has "11.5" normally.
|
|
|
|
|
+ // Or "bookworm/sid" on sid/testing.
|
|
|
slurp, _ := ioutil.ReadFile("/etc/debian_version")
|
|
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)
|
|
|
|
|
|
|
+ if v := string(bytes.TrimSpace(slurp)); v != "" {
|
|
|
|
|
+ if '0' <= v[0] && v[0] <= '9' {
|
|
|
|
|
+ meta.DistroVersion = v
|
|
|
|
|
+ } else if meta.DistroCodeName == "" {
|
|
|
|
|
+ meta.DistroCodeName = v
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- 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)
|
|
|
|
|
|
|
+ case "", "centos": // CentOS 6 has no /etc/os-release, so its id is ""
|
|
|
|
|
+ if meta.DistroVersion == "" {
|
|
|
|
|
+ if cr, _ := ioutil.ReadFile("/etc/centos-release"); len(cr) > 0 { // "CentOS release 6.10 (Final)
|
|
|
|
|
+ meta.DistroVersion = string(bytes.TrimSpace(cr))
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ if v := m["PRETTY_NAME"]; v != "" && meta.DistroVersion == "" && !strings.HasSuffix(v, "/sid") {
|
|
|
|
|
+ meta.DistroVersion = v
|
|
|
|
|
+ }
|
|
|
switch dist {
|
|
switch dist {
|
|
|
case distro.Synology:
|
|
case distro.Synology:
|
|
|
- return fmt.Sprintf("Synology %s%s", m["productversion"], attr)
|
|
|
|
|
|
|
+ meta.DistroVersion = m["productversion"]
|
|
|
case distro.OpenWrt:
|
|
case distro.OpenWrt:
|
|
|
- return fmt.Sprintf("OpenWrt %s%s", m["DISTRIB_RELEASE"], attr)
|
|
|
|
|
- case distro.Gokrazy:
|
|
|
|
|
- return fmt.Sprintf("Gokrazy%s", attr)
|
|
|
|
|
|
|
+ meta.DistroVersion = m["DISTRIB_RELEASE"]
|
|
|
}
|
|
}
|
|
|
- return fmt.Sprintf("Other%s", attr)
|
|
|
|
|
|
|
+ return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func packageTypeLinux() string {
|
|
func packageTypeLinux() string {
|