From 408005be94ba0a5e660e6e9567411436d2fc8ad4 Mon Sep 17 00:00:00 2001 From: James Nugent Date: Tue, 14 Mar 2017 12:11:30 -0500 Subject: [PATCH] host: Add Solaris support for Info, {Boot,Up}time This commit adds support for Info(), BootTime() and Uptime() in package Host. It uses no cgo, preferring to parse the output of `kstat -p` instead. Thanks go to @gfrey for the parsing logic for `/etc/release` and `uname`. --- host/host_fallback.go | 2 +- host/host_solaris.go | 132 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 host/host_solaris.go diff --git a/host/host_fallback.go b/host/host_fallback.go index 0adcdf2..bfd0143 100644 --- a/host/host_fallback.go +++ b/host/host_fallback.go @@ -1,4 +1,4 @@ -// +build !darwin,!linux,!freebsd,!openbsd,!windows +// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows package host diff --git a/host/host_solaris.go b/host/host_solaris.go new file mode 100644 index 0000000..79e25d5 --- /dev/null +++ b/host/host_solaris.go @@ -0,0 +1,132 @@ +package host + +import ( + "bufio" + "fmt" + "io/ioutil" + "os" + "os/exec" + "regexp" + "runtime" + "strconv" + "strings" + "time" + + "github.com/shirou/gopsutil/internal/common" +) + +func Info() (*InfoStat, error) { + result := &InfoStat{ + OS: runtime.GOOS, + } + + hostname, err := os.Hostname() + if err != nil { + return nil, err + } + result.Hostname = hostname + + // Parse versions from output of `uname(1)` + uname, err := exec.LookPath("/usr/bin/uname") + if err != nil { + return nil, err + } + + out, err := invoke.Command(uname, "-srv") + if err != nil { + return nil, err + } + + fields := strings.Fields(string(out)) + if len(fields) >= 1 { + result.PlatformFamily = fields[0] + } + if len(fields) >= 2 { + result.KernelVersion = fields[1] + } + if len(fields) == 3 { + result.PlatformVersion = fields[2] + } + + // Find distribution name from /etc/release + fh, err := os.Open("/etc/release") + if err != nil { + return nil, err + } + defer fh.Close() + + sc := bufio.NewScanner(fh) + if sc.Scan() { + line := strings.TrimSpace(sc.Text()) + switch { + case strings.HasPrefix(line, "SmartOS"): + result.Platform = "SmartOS" + case strings.HasPrefix(line, "OpenIndiana"): + result.Platform = "OpenIndiana" + case strings.HasPrefix(line, "OmniOS"): + result.Platform = "OmniOS" + case strings.HasPrefix(line, "Open Storage"): + result.Platform = "NexentaStor" + case strings.HasPrefix(line, "Solaris"): + result.Platform = "Solaris" + case strings.HasPrefix(line, "Oracle Solaris"): + result.Platform = "Solaris" + default: + result.Platform = strings.Fields(line)[0] + } + } + + // Find the boot time and calculate uptime relative to it + bootTime, err := BootTime() + if err != nil { + return nil, err + } + result.BootTime = bootTime + result.Uptime = uptimeSince(bootTime) + + // Count number of processes based on the number of entries in /proc + dirs, err := ioutil.ReadDir("/proc") + if err != nil { + return nil, err + } + result.Procs = uint64(len(dirs)) + + return result, nil +} + +var kstatMatch = regexp.MustCompile(`([^\s]+)[\s]+([^\s]*)`) + +func BootTime() (uint64, error) { + kstat, err := exec.LookPath("/usr/bin/kstat") + if err != nil { + return 0, err + } + + out, err := invoke.Command(kstat, "-p", "unix:0:system_misc:boot_time") + if err != nil { + return 0, err + } + + kstats := kstatMatch.FindAllStringSubmatch(string(out), -1) + if len(kstats) != 1 { + return 0, fmt.Errorf("Expected 1 kstat, found %d", len(kstats)) + } + + return strconv.ParseUint(kstats[0][2], 10, 64) +} + +func Uptime() (uint64, error) { + bootTime, err := BootTime() + if err != nil { + return 0, err + } + return uptimeSince(bootTime), nil +} + +func uptimeSince(since uint64) uint64 { + return uint64(time.Now().Unix()) - since +} + +func Users() ([]UserStat, error) { + return []UserStat{}, common.ErrNotImplementedError +}