PKGBUILD/vendor/periph.io/x/periph/host/distro/distro.go
2018-12-07 20:42:30 +01:00

190 lines
4.4 KiB
Go

// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Package distro implements common functionality to auto-detect features on
// the host; generally about linux distributions.
//
// Most of the functions exported as in the form IsFoo() where Foo is a linux
// distribution.
package distro
import (
"io/ioutil"
"os"
"strconv"
"strings"
"sync"
"unicode"
)
// IsArmbian returns true if running on a Armbian distribution.
//
// http://www.armbian.com/
func IsArmbian() bool {
if isArm && isLinux {
// Armbian presents itself as debian in /etc/os-release so OSRelease()
// cannot be used..
_, err := os.Stat("/etc/armbian.txt")
return err == nil
}
return false
}
// IsDebian returns true if running on an Debian derived distribution.
//
// This function returns true on both Armbian, Raspbian and Ubuntu.
//
// https://debian.org/
func IsDebian() bool {
if isLinux {
// http://0pointer.de/public/systemd-man/os-release.html#ID_LIKE=
if OSRelease()["ID"] == "debian" {
return true
}
for _, part := range strings.Split(OSRelease()["ID_LIKE"], " ") {
if part == "debian" {
return true
}
}
}
return false
}
// IsRaspbian returns true if running on a Raspbian distribution.
//
// https://raspbian.org/
func IsRaspbian() bool {
if isArm && isLinux {
return OSRelease()["ID"] == "raspbian"
}
return false
}
// IsUbuntu returns true if running on an Ubuntu derived distribution.
//
// https://ubuntu.com/
func IsUbuntu() bool {
if isLinux {
return OSRelease()["ID"] == "ubuntu"
}
return false
}
// OSRelease returns parsed data from /etc/os-release.
//
// For more information, see
// http://0pointer.de/public/systemd-man/os-release.html
func OSRelease() map[string]string {
if isLinux {
return makeOSReleaseLinux()
}
return osRelease
}
// CPU
// CPUInfo returns parsed data from /proc/cpuinfo.
func CPUInfo() map[string]string {
if isLinux {
return makeCPUInfoLinux()
}
return cpuInfo
}
//
var (
mu sync.Mutex
cpuInfo map[string]string
osRelease map[string]string
readFile = ioutil.ReadFile
)
func splitSemiColon(content string) map[string]string {
// Strictly speaking this format isn't ok, there can be multiple group.
out := map[string]string{}
for _, line := range strings.Split(content, "\n") {
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
// This format may have space around the ':'.
key := strings.TrimRightFunc(parts[0], unicode.IsSpace)
if len(key) == 0 || key[0] == '#' {
continue
}
// Ignore duplicate keys.
// TODO(maruel): Keep them all.
if _, ok := out[key]; !ok {
// Trim on both side, trailing space was observed on "Features" value.
out[key] = strings.TrimFunc(parts[1], unicode.IsSpace)
}
}
return out
}
func splitStrict(content string) map[string]string {
out := map[string]string{}
for _, line := range strings.Split(content, "\n") {
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
continue
}
key := parts[0]
if len(key) == 0 || key[0] == '#' {
continue
}
// Overwrite previous key.
value := parts[1]
if len(value) > 2 && value[0] == '"' && value[len(value)-1] == '"' {
// Not exactly 100% right but #closeenough. See for more details
// https://www.freedesktop.org/software/systemd/man/os-release.html
var err error
value, err = strconv.Unquote(value)
if err != nil {
continue
}
}
out[key] = value
}
return out
}
// splitNull returns the null-terminated strings in the data
func splitNull(data []byte) []string {
ss := strings.Split(string(data), "\x00")
// The last string is typically null-terminated, so remove empty string
// from end of array.
if len(ss) > 0 && len(ss[len(ss)-1]) == 0 {
ss = ss[:len(ss)-1]
}
return ss
}
func makeCPUInfoLinux() map[string]string {
mu.Lock()
defer mu.Unlock()
if cpuInfo == nil {
cpuInfo = map[string]string{}
if bytes, err := readFile("/proc/cpuinfo"); err == nil {
cpuInfo = splitSemiColon(string(bytes))
}
}
return cpuInfo
}
func makeOSReleaseLinux() map[string]string {
mu.Lock()
defer mu.Unlock()
if osRelease == nil {
// This file may not exist on older distros. Send a PR if you want to have
// a specific fallback.
osRelease = map[string]string{}
if bytes, err := readFile("/etc/os-release"); err == nil {
osRelease = splitStrict(string(bytes))
}
}
return osRelease
}