From 05ade19302357eba6a24348f31df140ce0eca326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kurk=C3=B3=20Mih=C3=A1ly?= Date: Tue, 23 Jan 2018 22:51:04 +0200 Subject: dashboard: CPU, memory, diskIO and traffic on the footer (#15950) * dashboard: footer, deep state update * dashboard: resolve asset path * dashboard: prevent state update on every reconnection * dashboard: fix linter issue * dashboard, cmd: minor UI fix, include commit hash * dashboard: gitCommit renamed to commit * dashboard: move the geth version to the right, make commit optional * dashboard: memory, traffic and CPU on footer * dashboard: fix merge * dashboard: CPU, diskIO on footer * dashboard: rename variables, use group declaration * dashboard: docs --- .../github.com/elastic/gosigar/sys/windows/doc.go | 2 + .../elastic/gosigar/sys/windows/ntquery.go | 132 +++++++ .../elastic/gosigar/sys/windows/privileges.go | 272 +++++++++++++++ .../elastic/gosigar/sys/windows/syscall_windows.go | 385 +++++++++++++++++++++ .../elastic/gosigar/sys/windows/version.go | 43 +++ .../gosigar/sys/windows/zsyscall_windows.go | 260 ++++++++++++++ 6 files changed, 1094 insertions(+) create mode 100644 vendor/github.com/elastic/gosigar/sys/windows/doc.go create mode 100644 vendor/github.com/elastic/gosigar/sys/windows/ntquery.go create mode 100644 vendor/github.com/elastic/gosigar/sys/windows/privileges.go create mode 100644 vendor/github.com/elastic/gosigar/sys/windows/syscall_windows.go create mode 100644 vendor/github.com/elastic/gosigar/sys/windows/version.go create mode 100644 vendor/github.com/elastic/gosigar/sys/windows/zsyscall_windows.go (limited to 'vendor/github.com/elastic/gosigar/sys') diff --git a/vendor/github.com/elastic/gosigar/sys/windows/doc.go b/vendor/github.com/elastic/gosigar/sys/windows/doc.go new file mode 100644 index 000000000..dda57aa83 --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/windows/doc.go @@ -0,0 +1,2 @@ +// Package windows contains various Windows system call. +package windows diff --git a/vendor/github.com/elastic/gosigar/sys/windows/ntquery.go b/vendor/github.com/elastic/gosigar/sys/windows/ntquery.go new file mode 100644 index 000000000..85de365e1 --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/windows/ntquery.go @@ -0,0 +1,132 @@ +// +build windows + +package windows + +import ( + "bytes" + "encoding/binary" + "io" + "runtime" + "syscall" + "time" + "unsafe" + + "github.com/pkg/errors" +) + +// On both 32-bit and 64-bit systems NtQuerySystemInformation expects the +// size of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION to be 48. +const sizeofSystemProcessorPerformanceInformation = 48 + +// ProcessBasicInformation is an equivalent representation of +// PROCESS_BASIC_INFORMATION in the Windows API. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx +type ProcessBasicInformation struct { + ExitStatus uint + PebBaseAddress uintptr + AffinityMask uint + BasePriority uint + UniqueProcessID uint + InheritedFromUniqueProcessID uint +} + +// NtQueryProcessBasicInformation queries basic information about the process +// associated with the given handle (provided by OpenProcess). It uses the +// NtQueryInformationProcess function to collect the data. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx +func NtQueryProcessBasicInformation(handle syscall.Handle) (ProcessBasicInformation, error) { + var processBasicInfo ProcessBasicInformation + processBasicInfoPtr := (*byte)(unsafe.Pointer(&processBasicInfo)) + size := uint32(unsafe.Sizeof(processBasicInfo)) + ntStatus, _ := _NtQueryInformationProcess(handle, 0, processBasicInfoPtr, size, nil) + if ntStatus != 0 { + return ProcessBasicInformation{}, errors.Errorf("NtQueryInformationProcess failed, NTSTATUS=0x%X", ntStatus) + } + + return processBasicInfo, nil +} + +// SystemProcessorPerformanceInformation contains CPU performance information +// for a single CPU. +type SystemProcessorPerformanceInformation struct { + IdleTime time.Duration // Amount of time spent idle. + KernelTime time.Duration // Kernel time does NOT include time spent in idle. + UserTime time.Duration // Amount of time spent executing in user mode. +} + +// _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION is an equivalent representation of +// SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION in the Windows API. This struct is +// used internally with NtQuerySystemInformation call and is not exported. The +// exported equivalent is SystemProcessorPerformanceInformation. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx +type _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION struct { + IdleTime int64 + KernelTime int64 + UserTime int64 + Reserved1 [2]int64 + Reserved2 uint32 +} + +// NtQuerySystemProcessorPerformanceInformation queries CPU performance +// information for each CPU. It uses the NtQuerySystemInformation function to +// collect the SystemProcessorPerformanceInformation. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx +func NtQuerySystemProcessorPerformanceInformation() ([]SystemProcessorPerformanceInformation, error) { + // NTSTATUS code for success. + // https://msdn.microsoft.com/en-us/library/cc704588.aspx + const STATUS_SUCCESS = 0 + + // From the _SYSTEM_INFORMATION_CLASS enum. + // http://processhacker.sourceforge.net/doc/ntexapi_8h.html#ad5d815b48e8f4da1ef2eb7a2f18a54e0 + const systemProcessorPerformanceInformation = 8 + + // Create a buffer large enough to hold an entry for each processor. + b := make([]byte, runtime.NumCPU()*sizeofSystemProcessorPerformanceInformation) + + // Query the performance information. Note that this function uses 0 to + // indicate success. Most other Windows functions use non-zero for success. + var returnLength uint32 + ntStatus, _ := _NtQuerySystemInformation(systemProcessorPerformanceInformation, &b[0], uint32(len(b)), &returnLength) + if ntStatus != STATUS_SUCCESS { + return nil, errors.Errorf("NtQuerySystemInformation failed, NTSTATUS=0x%X, bufLength=%v, returnLength=%v", ntStatus, len(b), returnLength) + } + + return readSystemProcessorPerformanceInformationBuffer(b) +} + +// readSystemProcessorPerformanceInformationBuffer reads from a buffer +// containing SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION data. The buffer should +// contain one entry for each CPU. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx +func readSystemProcessorPerformanceInformationBuffer(b []byte) ([]SystemProcessorPerformanceInformation, error) { + n := len(b) / sizeofSystemProcessorPerformanceInformation + r := bytes.NewReader(b) + + rtn := make([]SystemProcessorPerformanceInformation, 0, n) + for i := 0; i < n; i++ { + _, err := r.Seek(int64(i*sizeofSystemProcessorPerformanceInformation), io.SeekStart) + if err != nil { + return nil, errors.Wrapf(err, "failed to seek to cpuN=%v in buffer", i) + } + + times := make([]uint64, 3) + for j := range times { + err := binary.Read(r, binary.LittleEndian, ×[j]) + if err != nil { + return nil, errors.Wrapf(err, "failed reading cpu times for cpuN=%v", i) + } + } + + idleTime := time.Duration(times[0] * 100) + kernelTime := time.Duration(times[1] * 100) + userTime := time.Duration(times[2] * 100) + + rtn = append(rtn, SystemProcessorPerformanceInformation{ + IdleTime: idleTime, + KernelTime: kernelTime - idleTime, // Subtract out idle time from kernel time. + UserTime: userTime, + }) + } + + return rtn, nil +} diff --git a/vendor/github.com/elastic/gosigar/sys/windows/privileges.go b/vendor/github.com/elastic/gosigar/sys/windows/privileges.go new file mode 100644 index 000000000..28c78fd22 --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/windows/privileges.go @@ -0,0 +1,272 @@ +// +build windows + +package windows + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "runtime" + "strings" + "sync" + "syscall" + + "github.com/pkg/errors" + "golang.org/x/sys/windows" +) + +// Cache of privilege names to LUIDs. +var ( + privNames = make(map[string]int64) + privNameMutex sync.Mutex +) + +const ( + // SeDebugPrivilege is the name of the privilege used to debug programs. + SeDebugPrivilege = "SeDebugPrivilege" +) + +// Errors returned by AdjustTokenPrivileges. +const ( + ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300 +) + +// Attribute bits for privileges. +const ( + _SE_PRIVILEGE_ENABLED_BY_DEFAULT uint32 = 0x00000001 + _SE_PRIVILEGE_ENABLED uint32 = 0x00000002 + _SE_PRIVILEGE_REMOVED uint32 = 0x00000004 + _SE_PRIVILEGE_USED_FOR_ACCESS uint32 = 0x80000000 +) + +// Privilege contains information about a single privilege associated with a +// Token. +type Privilege struct { + LUID int64 `json:"-"` // Locally unique identifier (guaranteed only until the system is restarted). + Name string `json:"-"` + EnabledByDefault bool `json:"enabled_by_default,omitempty"` + Enabled bool `json:"enabled"` + Removed bool `json:"removed,omitempty"` + Used bool `json:"used,omitempty"` +} + +func (p Privilege) String() string { + var buf bytes.Buffer + buf.WriteString(p.Name) + buf.WriteString("=(") + + opts := make([]string, 0, 4) + if p.EnabledByDefault { + opts = append(opts, "Default") + } + if p.Enabled { + opts = append(opts, "Enabled") + } + if !p.EnabledByDefault && !p.Enabled { + opts = append(opts, "Disabled") + } + if p.Removed { + opts = append(opts, "Removed") + } + if p.Used { + opts = append(opts, "Used") + } + + buf.WriteString(strings.Join(opts, ", ")) + buf.WriteString(")") + + // Example: SeDebugPrivilege=(Default, Enabled) + return buf.String() +} + +// User represent the information about a Windows account. +type User struct { + SID string + Account string + Domain string + Type uint32 +} + +func (u User) String() string { + return fmt.Sprintf(`User:%v\%v, SID:%v, Type:%v`, u.Domain, u.Account, u.SID, u.Type) +} + +// DebugInfo contains general debug info about the current process. +type DebugInfo struct { + OSVersion Version // OS version info. + Arch string // Architecture of the machine. + NumCPU int // Number of CPUs. + User User // User that this process is running as. + ProcessPrivs map[string]Privilege // Privileges held by the process. +} + +func (d DebugInfo) String() string { + bytes, _ := json.Marshal(d) + return string(bytes) +} + +// LookupPrivilegeName looks up a privilege name given a LUID value. +func LookupPrivilegeName(systemName string, luid int64) (string, error) { + buf := make([]uint16, 256) + bufSize := uint32(len(buf)) + err := _LookupPrivilegeName(systemName, &luid, &buf[0], &bufSize) + if err != nil { + return "", errors.Wrapf(err, "LookupPrivilegeName failed for luid=%v", luid) + } + + return syscall.UTF16ToString(buf), nil +} + +// mapPrivileges maps privilege names to LUID values. +func mapPrivileges(names []string) ([]int64, error) { + var privileges []int64 + privNameMutex.Lock() + defer privNameMutex.Unlock() + for _, name := range names { + p, ok := privNames[name] + if !ok { + err := _LookupPrivilegeValue("", name, &p) + if err != nil { + return nil, errors.Wrapf(err, "LookupPrivilegeValue failed on '%v'", name) + } + privNames[name] = p + } + privileges = append(privileges, p) + } + return privileges, nil +} + +// EnableTokenPrivileges enables the specified privileges in the given +// Token. The token must have TOKEN_ADJUST_PRIVILEGES access. If the token +// does not already contain the privilege it cannot be enabled. +func EnableTokenPrivileges(token syscall.Token, privileges ...string) error { + privValues, err := mapPrivileges(privileges) + if err != nil { + return err + } + + var b bytes.Buffer + binary.Write(&b, binary.LittleEndian, uint32(len(privValues))) + for _, p := range privValues { + binary.Write(&b, binary.LittleEndian, p) + binary.Write(&b, binary.LittleEndian, uint32(_SE_PRIVILEGE_ENABLED)) + } + + success, err := _AdjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(b.Len()), nil, nil) + if !success { + return err + } + if err == ERROR_NOT_ALL_ASSIGNED { + return errors.Wrap(err, "error not all privileges were assigned") + } + + return nil +} + +// GetTokenPrivileges returns a list of privileges associated with a token. +// The provided token must have at a minimum TOKEN_QUERY access. This is a +// wrapper around the GetTokenInformation function. +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa446671(v=vs.85).aspx +func GetTokenPrivileges(token syscall.Token) (map[string]Privilege, error) { + // Determine the required buffer size. + var size uint32 + syscall.GetTokenInformation(token, syscall.TokenPrivileges, nil, 0, &size) + + // This buffer will receive a TOKEN_PRIVILEGE structure. + b := bytes.NewBuffer(make([]byte, size)) + err := syscall.GetTokenInformation(token, syscall.TokenPrivileges, &b.Bytes()[0], uint32(b.Len()), &size) + if err != nil { + return nil, errors.Wrap(err, "GetTokenInformation failed") + } + + var privilegeCount uint32 + err = binary.Read(b, binary.LittleEndian, &privilegeCount) + if err != nil { + return nil, errors.Wrap(err, "failed to read PrivilegeCount") + } + + rtn := make(map[string]Privilege, privilegeCount) + for i := 0; i < int(privilegeCount); i++ { + var luid int64 + err = binary.Read(b, binary.LittleEndian, &luid) + if err != nil { + return nil, errors.Wrap(err, "failed to read LUID value") + } + + var attributes uint32 + err = binary.Read(b, binary.LittleEndian, &attributes) + if err != nil { + return nil, errors.Wrap(err, "failed to read attributes") + } + + name, err := LookupPrivilegeName("", luid) + if err != nil { + return nil, errors.Wrapf(err, "LookupPrivilegeName failed for LUID=%v", luid) + } + + rtn[name] = Privilege{ + LUID: luid, + Name: name, + EnabledByDefault: (attributes & _SE_PRIVILEGE_ENABLED_BY_DEFAULT) > 0, + Enabled: (attributes & _SE_PRIVILEGE_ENABLED) > 0, + Removed: (attributes & _SE_PRIVILEGE_REMOVED) > 0, + Used: (attributes & _SE_PRIVILEGE_USED_FOR_ACCESS) > 0, + } + } + + return rtn, nil +} + +// GetTokenUser returns the User associated with the given Token. +func GetTokenUser(token syscall.Token) (User, error) { + tokenUser, err := token.GetTokenUser() + if err != nil { + return User{}, errors.Wrap(err, "GetTokenUser failed") + } + + var user User + user.SID, err = tokenUser.User.Sid.String() + if err != nil { + return user, errors.Wrap(err, "ConvertSidToStringSid failed") + } + + user.Account, user.Domain, user.Type, err = tokenUser.User.Sid.LookupAccount("") + if err != nil { + return user, errors.Wrap(err, "LookupAccountSid failed") + } + + return user, nil +} + +// GetDebugInfo returns general debug info about the current process. +func GetDebugInfo() (*DebugInfo, error) { + h, err := windows.GetCurrentProcess() + if err != nil { + return nil, err + } + + var token syscall.Token + err = syscall.OpenProcessToken(syscall.Handle(h), syscall.TOKEN_QUERY, &token) + if err != nil { + return nil, err + } + + privs, err := GetTokenPrivileges(token) + if err != nil { + return nil, err + } + + user, err := GetTokenUser(token) + if err != nil { + return nil, err + } + + return &DebugInfo{ + User: user, + ProcessPrivs: privs, + OSVersion: GetWindowsVersion(), + Arch: runtime.GOARCH, + NumCPU: runtime.NumCPU(), + }, nil +} diff --git a/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows.go b/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows.go new file mode 100644 index 000000000..88df0febf --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/windows/syscall_windows.go @@ -0,0 +1,385 @@ +package windows + +import ( + "fmt" + "syscall" + "time" + "unsafe" + + "github.com/pkg/errors" +) + +var ( + sizeofUint32 = 4 + sizeofProcessEntry32 = uint32(unsafe.Sizeof(ProcessEntry32{})) + sizeofProcessMemoryCountersEx = uint32(unsafe.Sizeof(ProcessMemoryCountersEx{})) + sizeofMemoryStatusEx = uint32(unsafe.Sizeof(MemoryStatusEx{})) +) + +// Process-specific access rights. Others are declared in the syscall package. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx +const ( + PROCESS_QUERY_LIMITED_INFORMATION uint32 = 0x1000 + PROCESS_VM_READ uint32 = 0x0010 +) + +// MAX_PATH is the maximum length for a path in Windows. +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx +const MAX_PATH = 260 + +// DriveType represents a type of drive (removable, fixed, CD-ROM, RAM disk, or +// network drive). +type DriveType uint32 + +// Drive types as returned by GetDriveType. +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364939(v=vs.85).aspx +const ( + DRIVE_UNKNOWN DriveType = iota + DRIVE_NO_ROOT_DIR + DRIVE_REMOVABLE + DRIVE_FIXED + DRIVE_REMOTE + DRIVE_CDROM + DRIVE_RAMDISK +) + +func (dt DriveType) String() string { + names := map[DriveType]string{ + DRIVE_UNKNOWN: "unknown", + DRIVE_NO_ROOT_DIR: "invalid", + DRIVE_REMOVABLE: "removable", + DRIVE_FIXED: "fixed", + DRIVE_REMOTE: "remote", + DRIVE_CDROM: "cdrom", + DRIVE_RAMDISK: "ramdisk", + } + + name, found := names[dt] + if !found { + return "unknown DriveType value" + } + return name +} + +// Flags that can be used with CreateToolhelp32Snapshot. +const ( + TH32CS_INHERIT uint32 = 0x80000000 // Indicates that the snapshot handle is to be inheritable. + TH32CS_SNAPHEAPLIST uint32 = 0x00000001 // Includes all heaps of the process specified in th32ProcessID in the snapshot. + TH32CS_SNAPMODULE uint32 = 0x00000008 // Includes all modules of the process specified in th32ProcessID in the snapshot. + TH32CS_SNAPMODULE32 uint32 = 0x00000010 // Includes all 32-bit modules of the process specified in th32ProcessID in the snapshot when called from a 64-bit process. + TH32CS_SNAPPROCESS uint32 = 0x00000002 // Includes all processes in the system in the snapshot. + TH32CS_SNAPTHREAD uint32 = 0x00000004 // Includes all threads in the system in the snapshot. +) + +// ProcessEntry32 is an equivalent representation of PROCESSENTRY32 in the +// Windows API. It contains a process's information. Do not modify or reorder. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684839(v=vs.85).aspx +type ProcessEntry32 struct { + size uint32 + CntUsage uint32 + ProcessID uint32 + DefaultHeapID uintptr + ModuleID uint32 + CntThreads uint32 + ParentProcessID uint32 + PriorityClassBase int32 + Flags uint32 + exeFile [MAX_PATH]uint16 +} + +// ExeFile returns the name of the executable file for the process. It does +// not contain the full path. +func (p ProcessEntry32) ExeFile() string { + return syscall.UTF16ToString(p.exeFile[:]) +} + +func (p ProcessEntry32) String() string { + return fmt.Sprintf("{CntUsage:%v ProcessID:%v DefaultHeapID:%v ModuleID:%v "+ + "CntThreads:%v ParentProcessID:%v PriorityClassBase:%v Flags:%v ExeFile:%v", + p.CntUsage, p.ProcessID, p.DefaultHeapID, p.ModuleID, p.CntThreads, + p.ParentProcessID, p.PriorityClassBase, p.Flags, p.ExeFile()) +} + +// MemoryStatusEx is an equivalent representation of MEMORYSTATUSEX in the +// Windows API. It contains information about the current state of both physical +// and virtual memory, including extended memory. +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770 +type MemoryStatusEx struct { + length uint32 + MemoryLoad uint32 + TotalPhys uint64 + AvailPhys uint64 + TotalPageFile uint64 + AvailPageFile uint64 + TotalVirtual uint64 + AvailVirtual uint64 + AvailExtendedVirtual uint64 +} + +// ProcessMemoryCountersEx is an equivalent representation of +// PROCESS_MEMORY_COUNTERS_EX in the Windows API. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684874(v=vs.85).aspx +type ProcessMemoryCountersEx struct { + cb uint32 + PageFaultCount uint32 + PeakWorkingSetSize uintptr + WorkingSetSize uintptr + QuotaPeakPagedPoolUsage uintptr + QuotaPagedPoolUsage uintptr + QuotaPeakNonPagedPoolUsage uintptr + QuotaNonPagedPoolUsage uintptr + PagefileUsage uintptr + PeakPagefileUsage uintptr + PrivateUsage uintptr +} + +// GetLogicalDriveStrings returns a list of drives in the system. +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364975(v=vs.85).aspx +func GetLogicalDriveStrings() ([]string, error) { + // Determine the size of the buffer required to receive all drives. + bufferLength, err := _GetLogicalDriveStringsW(0, nil) + if err != nil { + return nil, errors.Wrap(err, "GetLogicalDriveStringsW failed to get buffer length") + } + if bufferLength < 0 { + return nil, errors.New("GetLogicalDriveStringsW returned an invalid buffer length") + } + + buffer := make([]uint16, bufferLength) + _, err = _GetLogicalDriveStringsW(uint32(len(buffer)), &buffer[0]) + if err != nil { + return nil, errors.Wrap(err, "GetLogicalDriveStringsW failed") + } + + // Split the uint16 slice at null-terminators. + var startIdx int + var drivesUTF16 [][]uint16 + for i, value := range buffer { + if value == 0 { + drivesUTF16 = append(drivesUTF16, buffer[startIdx:i]) + startIdx = i + 1 + } + } + + // Convert the utf16 slices to strings. + drives := make([]string, 0, len(drivesUTF16)) + for _, driveUTF16 := range drivesUTF16 { + if len(driveUTF16) > 0 { + drives = append(drives, syscall.UTF16ToString(driveUTF16)) + } + } + + return drives, nil +} + +// GlobalMemoryStatusEx retrieves information about the system's current usage +// of both physical and virtual memory. +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366589(v=vs.85).aspx +func GlobalMemoryStatusEx() (MemoryStatusEx, error) { + memoryStatusEx := MemoryStatusEx{length: sizeofMemoryStatusEx} + err := _GlobalMemoryStatusEx(&memoryStatusEx) + if err != nil { + return MemoryStatusEx{}, errors.Wrap(err, "GlobalMemoryStatusEx failed") + } + + return memoryStatusEx, nil +} + +// GetProcessMemoryInfo retrieves information about the memory usage of the +// specified process. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683219(v=vs.85).aspx +func GetProcessMemoryInfo(handle syscall.Handle) (ProcessMemoryCountersEx, error) { + processMemoryCountersEx := ProcessMemoryCountersEx{cb: sizeofProcessMemoryCountersEx} + err := _GetProcessMemoryInfo(handle, &processMemoryCountersEx, processMemoryCountersEx.cb) + if err != nil { + return ProcessMemoryCountersEx{}, errors.Wrap(err, "GetProcessMemoryInfo failed") + } + + return processMemoryCountersEx, nil +} + +// GetProcessImageFileName Retrieves the name of the executable file for the +// specified process. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683217(v=vs.85).aspx +func GetProcessImageFileName(handle syscall.Handle) (string, error) { + buffer := make([]uint16, MAX_PATH) + _, err := _GetProcessImageFileName(handle, &buffer[0], uint32(len(buffer))) + if err != nil { + return "", errors.Wrap(err, "GetProcessImageFileName failed") + } + + return syscall.UTF16ToString(buffer), nil +} + +// GetSystemTimes retrieves system timing information. On a multiprocessor +// system, the values returned are the sum of the designated times across all +// processors. The returned kernel time does not include the system idle time. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724400(v=vs.85).aspx +func GetSystemTimes() (idle, kernel, user time.Duration, err error) { + var idleTime, kernelTime, userTime syscall.Filetime + err = _GetSystemTimes(&idleTime, &kernelTime, &userTime) + if err != nil { + return 0, 0, 0, errors.Wrap(err, "GetSystemTimes failed") + } + + idle = FiletimeToDuration(&idleTime) + kernel = FiletimeToDuration(&kernelTime) // Kernel time includes idle time so we subtract it out. + user = FiletimeToDuration(&userTime) + + return idle, kernel - idle, user, nil +} + +// FiletimeToDuration converts a Filetime to a time.Duration. Do not use this +// method to convert a Filetime to an actual clock time, for that use +// Filetime.Nanosecond(). +func FiletimeToDuration(ft *syscall.Filetime) time.Duration { + n := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime) // in 100-nanosecond intervals + return time.Duration(n * 100) +} + +// GetDriveType Determines whether a disk drive is a removable, fixed, CD-ROM, +// RAM disk, or network drive. A trailing backslash is required on the +// rootPathName. +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364939 +func GetDriveType(rootPathName string) (DriveType, error) { + rootPathNamePtr, err := syscall.UTF16PtrFromString(rootPathName) + if err != nil { + return DRIVE_UNKNOWN, errors.Wrapf(err, "UTF16PtrFromString failed for rootPathName=%v", rootPathName) + } + + dt, err := _GetDriveType(rootPathNamePtr) + if err != nil { + return DRIVE_UNKNOWN, errors.Wrapf(err, "GetDriveType failed for rootPathName=%v", rootPathName) + } + + return dt, nil +} + +// EnumProcesses retrieves the process identifier for each process object in the +// system. This function can return a max of 65536 PIDs. If there are more +// processes than that then this will not return them all. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682629(v=vs.85).aspx +func EnumProcesses() ([]uint32, error) { + enumProcesses := func(size int) ([]uint32, error) { + var ( + pids = make([]uint32, size) + sizeBytes = len(pids) * sizeofUint32 + bytesWritten uint32 + ) + + err := _EnumProcesses(&pids[0], uint32(sizeBytes), &bytesWritten) + + pidsWritten := int(bytesWritten) / sizeofUint32 + if int(bytesWritten)%sizeofUint32 != 0 || pidsWritten > len(pids) { + return nil, errors.Errorf("EnumProcesses returned an invalid bytesWritten value of %v", bytesWritten) + } + pids = pids[:pidsWritten] + + return pids, err + } + + // Retry the EnumProcesses call with larger arrays if needed. + size := 2048 + var pids []uint32 + for tries := 0; tries < 5; tries++ { + var err error + pids, err = enumProcesses(size) + if err != nil { + return nil, errors.Wrap(err, "EnumProcesses failed") + } + + if len(pids) < size { + break + } + + // Increase the size the pids array and retry the enumProcesses call + // because the array wasn't large enough to hold all of the processes. + size *= 2 + } + + return pids, nil +} + +// GetDiskFreeSpaceEx retrieves information about the amount of space that is +// available on a disk volume, which is the total amount of space, the total +// amount of free space, and the total amount of free space available to the +// user that is associated with the calling thread. +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx +func GetDiskFreeSpaceEx(directoryName string) (freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64, err error) { + directoryNamePtr, err := syscall.UTF16PtrFromString(directoryName) + if err != nil { + return 0, 0, 0, errors.Wrapf(err, "UTF16PtrFromString failed for directoryName=%v", directoryName) + } + + err = _GetDiskFreeSpaceEx(directoryNamePtr, &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes) + if err != nil { + return 0, 0, 0, err + } + + return freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes, nil +} + +// CreateToolhelp32Snapshot takes a snapshot of the specified processes, as well +// as the heaps, modules, and threads used by these processes. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682489(v=vs.85).aspx +func CreateToolhelp32Snapshot(flags, pid uint32) (syscall.Handle, error) { + h, err := _CreateToolhelp32Snapshot(flags, pid) + if err != nil { + return syscall.InvalidHandle, err + } + if h == syscall.InvalidHandle { + return syscall.InvalidHandle, syscall.GetLastError() + } + + return h, nil +} + +// Process32First retrieves information about the first process encountered in a +// system snapshot. +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684834 +func Process32First(handle syscall.Handle) (ProcessEntry32, error) { + processEntry32 := ProcessEntry32{size: sizeofProcessEntry32} + err := _Process32First(handle, &processEntry32) + if err != nil { + return ProcessEntry32{}, errors.Wrap(err, "Process32First failed") + } + + return processEntry32, nil +} + +// Process32Next retrieves information about the next process recorded in a +// system snapshot. When there are no more processes to iterate then +// syscall.ERROR_NO_MORE_FILES is returned (use errors.Cause() to unwrap). +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684836 +func Process32Next(handle syscall.Handle) (ProcessEntry32, error) { + processEntry32 := ProcessEntry32{size: sizeofProcessEntry32} + err := _Process32Next(handle, &processEntry32) + if err != nil { + return ProcessEntry32{}, errors.Wrap(err, "Process32Next failed") + } + + return processEntry32, nil +} + +// Use "GOOS=windows go generate -v -x ." to generate the source. + +// Add -trace to enable debug prints around syscalls. +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go + +// Windows API calls +//sys _GlobalMemoryStatusEx(buffer *MemoryStatusEx) (err error) = kernel32.GlobalMemoryStatusEx +//sys _GetLogicalDriveStringsW(bufferLength uint32, buffer *uint16) (length uint32, err error) = kernel32.GetLogicalDriveStringsW +//sys _GetProcessMemoryInfo(handle syscall.Handle, psmemCounters *ProcessMemoryCountersEx, cb uint32) (err error) = psapi.GetProcessMemoryInfo +//sys _GetProcessImageFileName(handle syscall.Handle, outImageFileName *uint16, size uint32) (length uint32, err error) = psapi.GetProcessImageFileNameW +//sys _GetSystemTimes(idleTime *syscall.Filetime, kernelTime *syscall.Filetime, userTime *syscall.Filetime) (err error) = kernel32.GetSystemTimes +//sys _GetDriveType(rootPathName *uint16) (dt DriveType, err error) = kernel32.GetDriveTypeW +//sys _EnumProcesses(processIds *uint32, sizeBytes uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses +//sys _GetDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailable *uint64, totalNumberOfBytes *uint64, totalNumberOfFreeBytes *uint64) (err error) = kernel32.GetDiskFreeSpaceExW +//sys _Process32First(handle syscall.Handle, processEntry32 *ProcessEntry32) (err error) = kernel32.Process32FirstW +//sys _Process32Next(handle syscall.Handle, processEntry32 *ProcessEntry32) (err error) = kernel32.Process32NextW +//sys _CreateToolhelp32Snapshot(flags uint32, processID uint32) (handle syscall.Handle, err error) = kernel32.CreateToolhelp32Snapshot +//sys _NtQuerySystemInformation(systemInformationClass uint32, systemInformation *byte, systemInformationLength uint32, returnLength *uint32) (ntstatus uint32, err error) = ntdll.NtQuerySystemInformation +//sys _NtQueryInformationProcess(processHandle syscall.Handle, processInformationClass uint32, processInformation *byte, processInformationLength uint32, returnLength *uint32) (ntstatus uint32, err error) = ntdll.NtQueryInformationProcess +//sys _LookupPrivilegeName(systemName string, luid *int64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW +//sys _LookupPrivilegeValue(systemName string, name string, luid *int64) (err error) = advapi32.LookupPrivilegeValueW +//sys _AdjustTokenPrivileges(token syscall.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges diff --git a/vendor/github.com/elastic/gosigar/sys/windows/version.go b/vendor/github.com/elastic/gosigar/sys/windows/version.go new file mode 100644 index 000000000..d0bca89c1 --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/windows/version.go @@ -0,0 +1,43 @@ +// +build windows + +package windows + +import ( + "fmt" + "syscall" +) + +// Version identifies a Windows version by major, minor, and build number. +type Version struct { + Major int + Minor int + Build int +} + +// GetWindowsVersion returns the Windows version information. Applications not +// manifested for Windows 8.1 or Windows 10 will return the Windows 8 OS version +// value (6.2). +// +// For a table of version numbers see: +// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx +func GetWindowsVersion() Version { + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx + ver, err := syscall.GetVersion() + if err != nil { + // GetVersion should never return an error. + panic(fmt.Errorf("GetVersion failed: %v", err)) + } + + return Version{ + Major: int(ver & 0xFF), + Minor: int(ver >> 8 & 0xFF), + Build: int(ver >> 16), + } +} + +// IsWindowsVistaOrGreater returns true if the Windows version is Vista or +// greater. +func (v Version) IsWindowsVistaOrGreater() bool { + // Vista is 6.0. + return v.Major >= 6 && v.Minor >= 0 +} diff --git a/vendor/github.com/elastic/gosigar/sys/windows/zsyscall_windows.go b/vendor/github.com/elastic/gosigar/sys/windows/zsyscall_windows.go new file mode 100644 index 000000000..53fae4e3b --- /dev/null +++ b/vendor/github.com/elastic/gosigar/sys/windows/zsyscall_windows.go @@ -0,0 +1,260 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package windows + +import "unsafe" +import "syscall" + +var _ unsafe.Pointer + +var ( + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + modpsapi = syscall.NewLazyDLL("psapi.dll") + modntdll = syscall.NewLazyDLL("ntdll.dll") + modadvapi32 = syscall.NewLazyDLL("advapi32.dll") + + procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") + procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW") + procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") + procGetProcessImageFileNameW = modpsapi.NewProc("GetProcessImageFileNameW") + procGetSystemTimes = modkernel32.NewProc("GetSystemTimes") + procGetDriveTypeW = modkernel32.NewProc("GetDriveTypeW") + procEnumProcesses = modpsapi.NewProc("EnumProcesses") + procGetDiskFreeSpaceExW = modkernel32.NewProc("GetDiskFreeSpaceExW") + procProcess32FirstW = modkernel32.NewProc("Process32FirstW") + procProcess32NextW = modkernel32.NewProc("Process32NextW") + procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot") + procNtQuerySystemInformation = modntdll.NewProc("NtQuerySystemInformation") + procNtQueryInformationProcess = modntdll.NewProc("NtQueryInformationProcess") + procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW") + procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") + procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") +) + +func _GlobalMemoryStatusEx(buffer *MemoryStatusEx) (err error) { + r1, _, e1 := syscall.Syscall(procGlobalMemoryStatusEx.Addr(), 1, uintptr(unsafe.Pointer(buffer)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _GetLogicalDriveStringsW(bufferLength uint32, buffer *uint16) (length uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetLogicalDriveStringsW.Addr(), 2, uintptr(bufferLength), uintptr(unsafe.Pointer(buffer)), 0) + length = uint32(r0) + if length == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _GetProcessMemoryInfo(handle syscall.Handle, psmemCounters *ProcessMemoryCountersEx, cb uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(psmemCounters)), uintptr(cb)) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _GetProcessImageFileName(handle syscall.Handle, outImageFileName *uint16, size uint32) (length uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetProcessImageFileNameW.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(outImageFileName)), uintptr(size)) + length = uint32(r0) + if length == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _GetSystemTimes(idleTime *syscall.Filetime, kernelTime *syscall.Filetime, userTime *syscall.Filetime) (err error) { + r1, _, e1 := syscall.Syscall(procGetSystemTimes.Addr(), 3, uintptr(unsafe.Pointer(idleTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _GetDriveType(rootPathName *uint16) (dt DriveType, err error) { + r0, _, e1 := syscall.Syscall(procGetDriveTypeW.Addr(), 1, uintptr(unsafe.Pointer(rootPathName)), 0, 0) + dt = DriveType(r0) + if dt == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _EnumProcesses(processIds *uint32, sizeBytes uint32, bytesReturned *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procEnumProcesses.Addr(), 3, uintptr(unsafe.Pointer(processIds)), uintptr(sizeBytes), uintptr(unsafe.Pointer(bytesReturned))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _GetDiskFreeSpaceEx(directoryName *uint16, freeBytesAvailable *uint64, totalNumberOfBytes *uint64, totalNumberOfFreeBytes *uint64) (err error) { + r1, _, e1 := syscall.Syscall6(procGetDiskFreeSpaceExW.Addr(), 4, uintptr(unsafe.Pointer(directoryName)), uintptr(unsafe.Pointer(freeBytesAvailable)), uintptr(unsafe.Pointer(totalNumberOfBytes)), uintptr(unsafe.Pointer(totalNumberOfFreeBytes)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _Process32First(handle syscall.Handle, processEntry32 *ProcessEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procProcess32FirstW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(processEntry32)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _Process32Next(handle syscall.Handle, processEntry32 *ProcessEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procProcess32NextW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(processEntry32)), 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _CreateToolhelp32Snapshot(flags uint32, processID uint32) (handle syscall.Handle, err error) { + r0, _, e1 := syscall.Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processID), 0) + handle = syscall.Handle(r0) + if handle == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _NtQuerySystemInformation(systemInformationClass uint32, systemInformation *byte, systemInformationLength uint32, returnLength *uint32) (ntstatus uint32, err error) { + r0, _, e1 := syscall.Syscall6(procNtQuerySystemInformation.Addr(), 4, uintptr(systemInformationClass), uintptr(unsafe.Pointer(systemInformation)), uintptr(systemInformationLength), uintptr(unsafe.Pointer(returnLength)), 0, 0) + ntstatus = uint32(r0) + if ntstatus == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _NtQueryInformationProcess(processHandle syscall.Handle, processInformationClass uint32, processInformation *byte, processInformationLength uint32, returnLength *uint32) (ntstatus uint32, err error) { + r0, _, e1 := syscall.Syscall6(procNtQueryInformationProcess.Addr(), 5, uintptr(processHandle), uintptr(processInformationClass), uintptr(unsafe.Pointer(processInformation)), uintptr(processInformationLength), uintptr(unsafe.Pointer(returnLength)), 0) + ntstatus = uint32(r0) + if ntstatus == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _LookupPrivilegeName(systemName string, luid *int64, buffer *uint16, size *uint32) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + return __LookupPrivilegeName(_p0, luid, buffer, size) +} + +func __LookupPrivilegeName(systemName *uint16, luid *int64, buffer *uint16, size *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _LookupPrivilegeValue(systemName string, name string, luid *int64) (err error) { + var _p0 *uint16 + _p0, err = syscall.UTF16PtrFromString(systemName) + if err != nil { + return + } + var _p1 *uint16 + _p1, err = syscall.UTF16PtrFromString(name) + if err != nil { + return + } + return __LookupPrivilegeValue(_p0, _p1, luid) +} + +func __LookupPrivilegeValue(systemName *uint16, name *uint16, luid *int64) (err error) { + r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func _AdjustTokenPrivileges(token syscall.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) { + var _p0 uint32 + if releaseAll { + _p0 = 1 + } else { + _p0 = 0 + } + r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize))) + success = r0 != 0 + if true { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} -- cgit v1.2.3