|
|
@ -15,7 +15,6 @@ import (
|
|
|
|
"runtime"
|
|
|
|
"runtime"
|
|
|
|
"strconv"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
|
"sync/atomic"
|
|
|
|
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/shirou/gopsutil/internal/common"
|
|
|
|
"github.com/shirou/gopsutil/internal/common"
|
|
|
@ -105,71 +104,13 @@ func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
|
|
|
return ret, nil
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// cachedBootTime must be accessed via atomic.Load/StoreUint64
|
|
|
|
|
|
|
|
var cachedBootTime uint64
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// BootTime returns the system boot time expressed in seconds since the epoch.
|
|
|
|
// BootTime returns the system boot time expressed in seconds since the epoch.
|
|
|
|
func BootTime() (uint64, error) {
|
|
|
|
func BootTime() (uint64, error) {
|
|
|
|
return BootTimeWithContext(context.Background())
|
|
|
|
return BootTimeWithContext(context.Background())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
|
|
|
func BootTimeWithContext(ctx context.Context) (uint64, error) {
|
|
|
|
t := atomic.LoadUint64(&cachedBootTime)
|
|
|
|
return common.BootTimeWithContext(ctx)
|
|
|
|
if t != 0 {
|
|
|
|
|
|
|
|
return t, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
system, role, err := Virtualization()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
statFile := "stat"
|
|
|
|
|
|
|
|
if system == "lxc" && role == "guest" {
|
|
|
|
|
|
|
|
// if lxc, /proc/uptime is used.
|
|
|
|
|
|
|
|
statFile = "uptime"
|
|
|
|
|
|
|
|
} else if system == "docker" && role == "guest" {
|
|
|
|
|
|
|
|
// also docker, guest
|
|
|
|
|
|
|
|
statFile = "uptime"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filename := common.HostProc(statFile)
|
|
|
|
|
|
|
|
lines, err := common.ReadLines(filename)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if statFile == "stat" {
|
|
|
|
|
|
|
|
for _, line := range lines {
|
|
|
|
|
|
|
|
if strings.HasPrefix(line, "btime") {
|
|
|
|
|
|
|
|
f := strings.Fields(line)
|
|
|
|
|
|
|
|
if len(f) != 2 {
|
|
|
|
|
|
|
|
return 0, fmt.Errorf("wrong btime format")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := strconv.ParseInt(f[1], 10, 64)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
t = uint64(b)
|
|
|
|
|
|
|
|
atomic.StoreUint64(&cachedBootTime, t)
|
|
|
|
|
|
|
|
return t, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if statFile == "uptime" {
|
|
|
|
|
|
|
|
if len(lines) != 1 {
|
|
|
|
|
|
|
|
return 0, fmt.Errorf("wrong uptime format")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
f := strings.Fields(lines[0])
|
|
|
|
|
|
|
|
b, err := strconv.ParseFloat(f[0], 64)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return 0, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
t = uint64(time.Now().Unix()) - uint64(b)
|
|
|
|
|
|
|
|
atomic.StoreUint64(&cachedBootTime, t)
|
|
|
|
|
|
|
|
return t, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0, fmt.Errorf("could not find btime")
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func uptime(boot uint64) uint64 {
|
|
|
|
func uptime(boot uint64) uint64 {
|
|
|
@ -235,26 +176,6 @@ func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func getOSRelease() (platform string, version string, err error) {
|
|
|
|
|
|
|
|
contents, err := common.ReadLines(common.HostEtc("os-release"))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return "", "", nil // return empty
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, line := range contents {
|
|
|
|
|
|
|
|
field := strings.Split(line, "=")
|
|
|
|
|
|
|
|
if len(field) < 2 {
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
switch field[0] {
|
|
|
|
|
|
|
|
case "ID": // use ID for lowercase
|
|
|
|
|
|
|
|
platform = strings.Trim(field[1], `"`)
|
|
|
|
|
|
|
|
case "VERSION":
|
|
|
|
|
|
|
|
version = strings.Trim(field[1], `"`)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return platform, version, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func getLSB() (*LSB, error) {
|
|
|
|
func getLSB() (*LSB, error) {
|
|
|
|
ret := &LSB{}
|
|
|
|
ret := &LSB{}
|
|
|
|
if common.PathExists(common.HostEtc("lsb-release")) {
|
|
|
|
if common.PathExists(common.HostEtc("lsb-release")) {
|
|
|
@ -392,7 +313,7 @@ func PlatformInformationWithContext(ctx context.Context) (platform string, famil
|
|
|
|
version = contents[0]
|
|
|
|
version = contents[0]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if common.PathExists(common.HostEtc("os-release")) {
|
|
|
|
} else if common.PathExists(common.HostEtc("os-release")) {
|
|
|
|
p, v, err := getOSRelease()
|
|
|
|
p, v, err := common.GetOSRelease()
|
|
|
|
if err == nil {
|
|
|
|
if err == nil {
|
|
|
|
platform = p
|
|
|
|
platform = p
|
|
|
|
version = v
|
|
|
|
version = v
|
|
|
@ -515,116 +436,7 @@ func Virtualization() (string, string, error) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
|
|
|
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
|
|
|
var system string
|
|
|
|
return common.VirtualizationWithContext(ctx)
|
|
|
|
var role string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filename := common.HostProc("xen")
|
|
|
|
|
|
|
|
if common.PathExists(filename) {
|
|
|
|
|
|
|
|
system = "xen"
|
|
|
|
|
|
|
|
role = "guest" // assume guest
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if common.PathExists(filepath.Join(filename, "capabilities")) {
|
|
|
|
|
|
|
|
contents, err := common.ReadLines(filepath.Join(filename, "capabilities"))
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
if common.StringsContains(contents, "control_d") {
|
|
|
|
|
|
|
|
role = "host"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filename = common.HostProc("modules")
|
|
|
|
|
|
|
|
if common.PathExists(filename) {
|
|
|
|
|
|
|
|
contents, err := common.ReadLines(filename)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
if common.StringsContains(contents, "kvm") {
|
|
|
|
|
|
|
|
system = "kvm"
|
|
|
|
|
|
|
|
role = "host"
|
|
|
|
|
|
|
|
} else if common.StringsContains(contents, "vboxdrv") {
|
|
|
|
|
|
|
|
system = "vbox"
|
|
|
|
|
|
|
|
role = "host"
|
|
|
|
|
|
|
|
} else if common.StringsContains(contents, "vboxguest") {
|
|
|
|
|
|
|
|
system = "vbox"
|
|
|
|
|
|
|
|
role = "guest"
|
|
|
|
|
|
|
|
} else if common.StringsContains(contents, "vmware") {
|
|
|
|
|
|
|
|
system = "vmware"
|
|
|
|
|
|
|
|
role = "guest"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filename = common.HostProc("cpuinfo")
|
|
|
|
|
|
|
|
if common.PathExists(filename) {
|
|
|
|
|
|
|
|
contents, err := common.ReadLines(filename)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
if common.StringsContains(contents, "QEMU Virtual CPU") ||
|
|
|
|
|
|
|
|
common.StringsContains(contents, "Common KVM processor") ||
|
|
|
|
|
|
|
|
common.StringsContains(contents, "Common 32-bit KVM processor") {
|
|
|
|
|
|
|
|
system = "kvm"
|
|
|
|
|
|
|
|
role = "guest"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filename = common.HostProc("bus/pci/devices")
|
|
|
|
|
|
|
|
if common.PathExists(filename) {
|
|
|
|
|
|
|
|
contents, err := common.ReadLines(filename)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
if common.StringsContains(contents, "virtio-pci") {
|
|
|
|
|
|
|
|
role = "guest"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filename = common.HostProc()
|
|
|
|
|
|
|
|
if common.PathExists(filepath.Join(filename, "bc", "0")) {
|
|
|
|
|
|
|
|
system = "openvz"
|
|
|
|
|
|
|
|
role = "host"
|
|
|
|
|
|
|
|
} else if common.PathExists(filepath.Join(filename, "vz")) {
|
|
|
|
|
|
|
|
system = "openvz"
|
|
|
|
|
|
|
|
role = "guest"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// not use dmidecode because it requires root
|
|
|
|
|
|
|
|
if common.PathExists(filepath.Join(filename, "self", "status")) {
|
|
|
|
|
|
|
|
contents, err := common.ReadLines(filepath.Join(filename, "self", "status"))
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if common.StringsContains(contents, "s_context:") ||
|
|
|
|
|
|
|
|
common.StringsContains(contents, "VxID:") {
|
|
|
|
|
|
|
|
system = "linux-vserver"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: guest or host
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if common.PathExists(filepath.Join(filename, "self", "cgroup")) {
|
|
|
|
|
|
|
|
contents, err := common.ReadLines(filepath.Join(filename, "self", "cgroup"))
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
|
|
if common.StringsContains(contents, "lxc") {
|
|
|
|
|
|
|
|
system = "lxc"
|
|
|
|
|
|
|
|
role = "guest"
|
|
|
|
|
|
|
|
} else if common.StringsContains(contents, "docker") {
|
|
|
|
|
|
|
|
system = "docker"
|
|
|
|
|
|
|
|
role = "guest"
|
|
|
|
|
|
|
|
} else if common.StringsContains(contents, "machine-rkt") {
|
|
|
|
|
|
|
|
system = "rkt"
|
|
|
|
|
|
|
|
role = "guest"
|
|
|
|
|
|
|
|
} else if common.PathExists("/usr/bin/lxc-version") {
|
|
|
|
|
|
|
|
system = "lxc"
|
|
|
|
|
|
|
|
role = "host"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if common.PathExists(common.HostEtc("os-release")) {
|
|
|
|
|
|
|
|
p, _, err := getOSRelease()
|
|
|
|
|
|
|
|
if err == nil && p == "coreos" {
|
|
|
|
|
|
|
|
system = "rkt" // Is it true?
|
|
|
|
|
|
|
|
role = "host"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return system, role, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func SensorsTemperatures() ([]TemperatureStat, error) {
|
|
|
|
func SensorsTemperatures() ([]TemperatureStat, error) {
|
|
|
|