mirror of
https://github.com/shirou/gopsutil.git
synced 2025-04-26 13:48:59 +08:00

All BSDs use the same implementation to get BootTime{,WithContext} and Uptime{,WithContext} based on the kern.boottime sysctl. Move this implementation to a separate host/host_bsd.go file shared by darwin, freebsd and openbsd. Also use SysctlTimeval to get the boot time directly as a type Timeval instead of manually extracting it using package unsafe. It will also allow for easier reuse to support package host on e.g. Dragonfly BSD or NetBSD. This requires updating the golang.org/x/sys/unix dependency to the latest revision. Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
210 lines
4.3 KiB
Go
210 lines
4.3 KiB
Go
// +build freebsd
|
|
|
|
package host
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/binary"
|
|
"io/ioutil"
|
|
"math"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
"unsafe"
|
|
|
|
"github.com/shirou/gopsutil/internal/common"
|
|
"github.com/shirou/gopsutil/process"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const (
|
|
UTNameSize = 16 /* see MAXLOGNAME in <sys/param.h> */
|
|
UTLineSize = 8
|
|
UTHostSize = 16
|
|
)
|
|
|
|
func Info() (*InfoStat, error) {
|
|
return InfoWithContext(context.Background())
|
|
}
|
|
|
|
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
|
|
ret := &InfoStat{
|
|
OS: runtime.GOOS,
|
|
PlatformFamily: "freebsd",
|
|
}
|
|
|
|
hostname, err := os.Hostname()
|
|
if err == nil {
|
|
ret.Hostname = hostname
|
|
}
|
|
|
|
platform, family, version, err := PlatformInformation()
|
|
if err == nil {
|
|
ret.Platform = platform
|
|
ret.PlatformFamily = family
|
|
ret.PlatformVersion = version
|
|
ret.KernelVersion = version
|
|
}
|
|
|
|
kernelArch, err := kernelArch()
|
|
if err == nil {
|
|
ret.KernelArch = kernelArch
|
|
}
|
|
|
|
system, role, err := Virtualization()
|
|
if err == nil {
|
|
ret.VirtualizationSystem = system
|
|
ret.VirtualizationRole = role
|
|
}
|
|
|
|
boot, err := BootTime()
|
|
if err == nil {
|
|
ret.BootTime = boot
|
|
ret.Uptime = uptime(boot)
|
|
}
|
|
|
|
procs, err := process.Pids()
|
|
if err == nil {
|
|
ret.Procs = uint64(len(procs))
|
|
}
|
|
|
|
hostid, err := unix.Sysctl("kern.hostuuid")
|
|
if err == nil && hostid != "" {
|
|
ret.HostID = strings.ToLower(hostid)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func Users() ([]UserStat, error) {
|
|
return UsersWithContext(context.Background())
|
|
}
|
|
|
|
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
|
|
utmpfile := "/var/run/utx.active"
|
|
if !common.PathExists(utmpfile) {
|
|
utmpfile = "/var/run/utmp" // before 9.0
|
|
return getUsersFromUtmp(utmpfile)
|
|
}
|
|
|
|
var ret []UserStat
|
|
file, err := os.Open(utmpfile)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
defer file.Close()
|
|
|
|
buf, err := ioutil.ReadAll(file)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
|
|
entrySize := sizeOfUtmpx
|
|
count := len(buf) / entrySize
|
|
|
|
for i := 0; i < count; i++ {
|
|
b := buf[i*sizeOfUtmpx : (i+1)*sizeOfUtmpx]
|
|
var u Utmpx
|
|
br := bytes.NewReader(b)
|
|
err := binary.Read(br, binary.BigEndian, &u)
|
|
if err != nil || u.Type != 4 {
|
|
continue
|
|
}
|
|
sec := math.Floor(float64(u.Tv) / 1000000)
|
|
user := UserStat{
|
|
User: common.IntToString(u.User[:]),
|
|
Terminal: common.IntToString(u.Line[:]),
|
|
Host: common.IntToString(u.Host[:]),
|
|
Started: int(sec),
|
|
}
|
|
|
|
ret = append(ret, user)
|
|
}
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
func PlatformInformation() (string, string, string, error) {
|
|
return PlatformInformationWithContext(context.Background())
|
|
}
|
|
|
|
func PlatformInformationWithContext(ctx context.Context) (string, string, string, error) {
|
|
platform, err := unix.Sysctl("kern.ostype")
|
|
if err != nil {
|
|
return "", "", "", err
|
|
}
|
|
|
|
version, err := unix.Sysctl("kern.osrelease")
|
|
if err != nil {
|
|
return "", "", "", err
|
|
}
|
|
|
|
return strings.ToLower(platform), "", strings.ToLower(version), nil
|
|
}
|
|
|
|
func Virtualization() (string, string, error) {
|
|
return VirtualizationWithContext(context.Background())
|
|
}
|
|
|
|
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
|
|
return "", "", common.ErrNotImplementedError
|
|
}
|
|
|
|
// before 9.0
|
|
func getUsersFromUtmp(utmpfile string) ([]UserStat, error) {
|
|
var ret []UserStat
|
|
file, err := os.Open(utmpfile)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
defer file.Close()
|
|
|
|
buf, err := ioutil.ReadAll(file)
|
|
if err != nil {
|
|
return ret, err
|
|
}
|
|
|
|
u := Utmp{}
|
|
entrySize := int(unsafe.Sizeof(u))
|
|
count := len(buf) / entrySize
|
|
|
|
for i := 0; i < count; i++ {
|
|
b := buf[i*entrySize : i*entrySize+entrySize]
|
|
var u Utmp
|
|
br := bytes.NewReader(b)
|
|
err := binary.Read(br, binary.LittleEndian, &u)
|
|
if err != nil || u.Time == 0 {
|
|
continue
|
|
}
|
|
user := UserStat{
|
|
User: common.IntToString(u.Name[:]),
|
|
Terminal: common.IntToString(u.Line[:]),
|
|
Host: common.IntToString(u.Host[:]),
|
|
Started: int(u.Time),
|
|
}
|
|
|
|
ret = append(ret, user)
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func SensorsTemperatures() ([]TemperatureStat, error) {
|
|
return SensorsTemperaturesWithContext(context.Background())
|
|
}
|
|
|
|
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
|
|
return []TemperatureStat{}, common.ErrNotImplementedError
|
|
}
|
|
|
|
func KernelVersion() (string, error) {
|
|
return KernelVersionWithContext(context.Background())
|
|
}
|
|
|
|
func KernelVersionWithContext(ctx context.Context) (string, error) {
|
|
_, _, version, err := PlatformInformation()
|
|
return version, err
|
|
}
|