237 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			237 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// +build windows
 | 
						|
 | 
						|
package host
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"runtime"
 | 
						|
	"strings"
 | 
						|
	"sync/atomic"
 | 
						|
	"time"
 | 
						|
	"unsafe"
 | 
						|
 | 
						|
	"github.com/StackExchange/wmi"
 | 
						|
	"github.com/shirou/gopsutil/internal/common"
 | 
						|
	process "github.com/shirou/gopsutil/process"
 | 
						|
	"golang.org/x/sys/windows"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	procGetSystemTimeAsFileTime = common.Modkernel32.NewProc("GetSystemTimeAsFileTime")
 | 
						|
	osInfo                      *Win32_OperatingSystem
 | 
						|
)
 | 
						|
 | 
						|
type Win32_OperatingSystem struct {
 | 
						|
	Version        string
 | 
						|
	Caption        string
 | 
						|
	ProductType    uint32
 | 
						|
	BuildNumber    string
 | 
						|
	LastBootUpTime time.Time
 | 
						|
}
 | 
						|
 | 
						|
func Info() (*InfoStat, error) {
 | 
						|
	return InfoWithContext(context.Background())
 | 
						|
}
 | 
						|
 | 
						|
func InfoWithContext(ctx context.Context) (*InfoStat, error) {
 | 
						|
	ret := &InfoStat{
 | 
						|
		OS: runtime.GOOS,
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		hostname, err := os.Hostname()
 | 
						|
		if err == nil {
 | 
						|
			ret.Hostname = hostname
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		platform, family, version, err := PlatformInformationWithContext(ctx)
 | 
						|
		if err == nil {
 | 
						|
			ret.Platform = platform
 | 
						|
			ret.PlatformFamily = family
 | 
						|
			ret.PlatformVersion = version
 | 
						|
		} else {
 | 
						|
			return ret, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		boot, err := BootTime()
 | 
						|
		if err == nil {
 | 
						|
			ret.BootTime = boot
 | 
						|
			ret.Uptime, _ = Uptime()
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		hostID, err := getMachineGuid()
 | 
						|
		if err == nil {
 | 
						|
			ret.HostID = strings.ToLower(hostID)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		procs, err := process.Pids()
 | 
						|
		if err == nil {
 | 
						|
			ret.Procs = uint64(len(procs))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return ret, nil
 | 
						|
}
 | 
						|
 | 
						|
func getMachineGuid() (string, error) {
 | 
						|
	var h windows.Handle
 | 
						|
	err := windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Cryptography`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
	defer windows.RegCloseKey(h)
 | 
						|
 | 
						|
	const windowsRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16
 | 
						|
	const uuidLen = 36
 | 
						|
 | 
						|
	var regBuf [windowsRegBufLen]uint16
 | 
						|
	bufLen := uint32(windowsRegBufLen)
 | 
						|
	var valType uint32
 | 
						|
	err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	hostID := windows.UTF16ToString(regBuf[:])
 | 
						|
	hostIDLen := len(hostID)
 | 
						|
	if hostIDLen != uuidLen {
 | 
						|
		return "", fmt.Errorf("HostID incorrect: %q\n", hostID)
 | 
						|
	}
 | 
						|
 | 
						|
	return hostID, nil
 | 
						|
}
 | 
						|
 | 
						|
func GetOSInfo() (Win32_OperatingSystem, error) {
 | 
						|
	return GetOSInfoWithContext(context.Background())
 | 
						|
}
 | 
						|
 | 
						|
func GetOSInfoWithContext(ctx context.Context) (Win32_OperatingSystem, error) {
 | 
						|
	var dst []Win32_OperatingSystem
 | 
						|
	q := wmi.CreateQuery(&dst, "")
 | 
						|
	err := common.WMIQueryWithContext(ctx, q, &dst)
 | 
						|
	if err != nil {
 | 
						|
		return Win32_OperatingSystem{}, err
 | 
						|
	}
 | 
						|
 | 
						|
	osInfo = &dst[0]
 | 
						|
 | 
						|
	return dst[0], nil
 | 
						|
}
 | 
						|
 | 
						|
func Uptime() (uint64, error) {
 | 
						|
	return UptimeWithContext(context.Background())
 | 
						|
}
 | 
						|
 | 
						|
func UptimeWithContext(ctx context.Context) (uint64, error) {
 | 
						|
	if osInfo == nil {
 | 
						|
		_, err := GetOSInfoWithContext(ctx)
 | 
						|
		if err != nil {
 | 
						|
			return 0, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	now := time.Now()
 | 
						|
	t := osInfo.LastBootUpTime.Local()
 | 
						|
	return uint64(now.Sub(t).Seconds()), nil
 | 
						|
}
 | 
						|
 | 
						|
func bootTime(up uint64) uint64 {
 | 
						|
	return uint64(time.Now().Unix()) - up
 | 
						|
}
 | 
						|
 | 
						|
// cachedBootTime must be accessed via atomic.Load/StoreUint64
 | 
						|
var cachedBootTime uint64
 | 
						|
 | 
						|
func BootTime() (uint64, error) {
 | 
						|
	return BootTimeWithContext(context.Background())
 | 
						|
}
 | 
						|
 | 
						|
func BootTimeWithContext(ctx context.Context) (uint64, error) {
 | 
						|
	t := atomic.LoadUint64(&cachedBootTime)
 | 
						|
	if t != 0 {
 | 
						|
		return t, nil
 | 
						|
	}
 | 
						|
	up, err := Uptime()
 | 
						|
	if err != nil {
 | 
						|
		return 0, err
 | 
						|
	}
 | 
						|
	t = bootTime(up)
 | 
						|
	atomic.StoreUint64(&cachedBootTime, t)
 | 
						|
	return t, nil
 | 
						|
}
 | 
						|
 | 
						|
func PlatformInformation() (platform string, family string, version string, err error) {
 | 
						|
	return PlatformInformationWithContext(context.Background())
 | 
						|
}
 | 
						|
 | 
						|
func PlatformInformationWithContext(ctx context.Context) (platform string, family string, version string, err error) {
 | 
						|
	if osInfo == nil {
 | 
						|
		_, err = GetOSInfoWithContext(ctx)
 | 
						|
		if err != nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Platform
 | 
						|
	platform = strings.Trim(osInfo.Caption, " ")
 | 
						|
 | 
						|
	// PlatformFamily
 | 
						|
	switch osInfo.ProductType {
 | 
						|
	case 1:
 | 
						|
		family = "Standalone Workstation"
 | 
						|
	case 2:
 | 
						|
		family = "Server (Domain Controller)"
 | 
						|
	case 3:
 | 
						|
		family = "Server"
 | 
						|
	}
 | 
						|
 | 
						|
	// Platform Version
 | 
						|
	version = fmt.Sprintf("%s Build %s", osInfo.Version, osInfo.BuildNumber)
 | 
						|
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func Users() ([]UserStat, error) {
 | 
						|
	return UsersWithContext(context.Background())
 | 
						|
}
 | 
						|
 | 
						|
func UsersWithContext(ctx context.Context) ([]UserStat, error) {
 | 
						|
	var ret []UserStat
 | 
						|
 | 
						|
	return ret, nil
 | 
						|
}
 | 
						|
 | 
						|
func SensorsTemperatures() ([]TemperatureStat, error) {
 | 
						|
	return SensorsTemperaturesWithContext(context.Background())
 | 
						|
}
 | 
						|
 | 
						|
func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
 | 
						|
	return []TemperatureStat{}, common.ErrNotImplementedError
 | 
						|
}
 | 
						|
 | 
						|
func Virtualization() (string, string, error) {
 | 
						|
	return VirtualizationWithContext(context.Background())
 | 
						|
}
 | 
						|
 | 
						|
func VirtualizationWithContext(ctx context.Context) (string, string, error) {
 | 
						|
	return "", "", common.ErrNotImplementedError
 | 
						|
}
 | 
						|
 | 
						|
func KernelVersion() (string, error) {
 | 
						|
	return KernelVersionWithContext(context.Background())
 | 
						|
}
 | 
						|
 | 
						|
func KernelVersionWithContext(ctx context.Context) (string, error) {
 | 
						|
	_, _, version, err := PlatformInformation()
 | 
						|
	return version, err
 | 
						|
}
 |