diff --git a/.gitignore b/.gitignore index 88350849c..d7d43b843 100644 --- a/.gitignore +++ b/.gitignore @@ -105,6 +105,3 @@ azure-hashistack.pem # generated keys for e2e tests e2e/terraform/keys/ - -# darwin CGO files copied for build -vendor/github.com/shirou/gopsutil/host/include/ diff --git a/GNUmakefile b/GNUmakefile index 08a592333..76ed65e09 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -45,8 +45,6 @@ endif ifeq (Darwin,$(THIS_OS)) ALL_TARGETS += darwin_amd64 # Copy CGO files for darwin into place -# TODO(shoenig) remove pending github.com/shirou/gopsutil/pull/885 -$(shell cp -R lib/darwin/include vendor/github.com/shirou/gopsutil/host) endif # On FreeBSD, we only build for FreeBSD diff --git a/go.mod b/go.mod index 714f66cea..6a9e11d83 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ replace ( github.com/godbus/dbus => github.com/godbus/dbus v5.0.1+incompatible github.com/hashicorp/nomad/api => ./api github.com/kr/pty => github.com/kr/pty v1.1.5 + github.com/shirou/gopsutil => github.com/hashicorp/gopsutil v2.18.13-0.20200531184148-5aca383d4f9d+incompatible ) require ( diff --git a/go.sum b/go.sum index bdd9861ea..344ae7016 100644 --- a/go.sum +++ b/go.sum @@ -389,6 +389,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/gopsutil v2.18.13-0.20200531184148-5aca383d4f9d+incompatible h1:3dtKc7GWJY4Mm85E1kczAN4JuBFM3kamwt5Zx426Yl8= +github.com/hashicorp/gopsutil v2.18.13-0.20200531184148-5aca383d4f9d+incompatible/go.mod h1:Mz8xr0ujmCW1qsmWMIUDOc+RgaN9QMvrgnBzQF12nYM= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.1-0.20191016231534-914dc3f8dd7c h1:PdZEHcpa3117kJ1Wa5EYupzCzn9QlBby8Fx2YpZPYvo= github.com/hashicorp/hcl v1.0.1-0.20191016231534-914dc3f8dd7c/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= @@ -651,9 +653,6 @@ github.com/seccomp/libseccomp-golang v0.9.2-0.20200314001724-bdab42bd5128 h1:vWI github.com/seccomp/libseccomp-golang v0.9.2-0.20200314001724-bdab42bd5128/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shirou/gopsutil v0.0.0-20181107111621-48177ef5f880/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil v2.20.2+incompatible h1:ucK79BhBpgqQxPASyS2cu9HX8cfDVljBN1WWFvbNvgY= -github.com/shirou/gopsutil v2.20.2+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu.go b/vendor/github.com/shirou/gopsutil/cpu/cpu.go index 2372ce33d..d3ea1f245 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu.go @@ -14,8 +14,7 @@ import ( ) // TimesStat contains the amounts of time the CPU has spent performing different -// kinds of work. Time units are in USER_HZ or Jiffies (typically hundredths of -// a second). It is based on linux /proc/stat file. +// kinds of work. Time units are in seconds. It is based on linux /proc/stat file. type TimesStat struct { CPU string `json:"cpu"` User float64 `json:"user"` diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin.go index cd0475d3c..3d3455ee6 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_darwin.go @@ -4,6 +4,7 @@ package cpu import ( "context" + "os/exec" "strconv" "strings" @@ -23,6 +24,21 @@ const ( // default value. from time.h var ClocksPerSec = float64(128) +func init() { + getconf, err := exec.LookPath("getconf") + if err != nil { + return + } + out, err := invoke.Command(getconf, "CLK_TCK") + // ignore errors + if err == nil { + i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64) + if err == nil { + ClocksPerSec = float64(i) + } + } +} + func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go index 0b9e9d2b6..735bd29ed 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go @@ -13,7 +13,7 @@ import ( "github.com/shirou/gopsutil/internal/common" ) -var CPUTick = float64(100) +var ClocksPerSec = float64(100) func init() { getconf, err := exec.LookPath("getconf") @@ -25,7 +25,7 @@ func init() { if err == nil { i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64) if err == nil { - CPUTick = i + ClocksPerSec = i } } } @@ -250,34 +250,34 @@ func parseStatLine(line string) (*TimesStat, error) { ct := &TimesStat{ CPU: cpu, - User: user / CPUTick, - Nice: nice / CPUTick, - System: system / CPUTick, - Idle: idle / CPUTick, - Iowait: iowait / CPUTick, - Irq: irq / CPUTick, - Softirq: softirq / CPUTick, + User: user / ClocksPerSec, + Nice: nice / ClocksPerSec, + System: system / ClocksPerSec, + Idle: idle / ClocksPerSec, + Iowait: iowait / ClocksPerSec, + Irq: irq / ClocksPerSec, + Softirq: softirq / ClocksPerSec, } if len(fields) > 8 { // Linux >= 2.6.11 steal, err := strconv.ParseFloat(fields[8], 64) if err != nil { return nil, err } - ct.Steal = steal / CPUTick + ct.Steal = steal / ClocksPerSec } if len(fields) > 9 { // Linux >= 2.6.24 guest, err := strconv.ParseFloat(fields[9], 64) if err != nil { return nil, err } - ct.Guest = guest / CPUTick + ct.Guest = guest / ClocksPerSec } if len(fields) > 10 { // Linux >= 3.2.0 guestNice, err := strconv.ParseFloat(fields[10], 64) if err != nil { return nil, err } - ct.GuestNice = guestNice / CPUTick + ct.GuestNice = guestNice / ClocksPerSec } return ct, nil diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go index 97c0e342f..ad1750b5c 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go @@ -50,7 +50,7 @@ type Win32_PerfFormattedData_PerfOS_System struct { } const ( - win32_TicksPerSecond = 10000000.0 + ClocksPerSec = 10000000.0 // systemProcessorPerformanceInformationClass information class to query with NTQuerySystemInformation // https://processhacker.sourceforge.io/doc/ntexapi_8h.html#ad5d815b48e8f4da1ef2eb7a2f18a54e0 @@ -159,10 +159,10 @@ func perCPUTimes() ([]TimesStat, error) { for core, v := range stats { c := TimesStat{ CPU: fmt.Sprintf("cpu%d", core), - User: float64(v.UserTime) / win32_TicksPerSecond, - System: float64(v.KernelTime-v.IdleTime) / win32_TicksPerSecond, - Idle: float64(v.IdleTime) / win32_TicksPerSecond, - Irq: float64(v.InterruptTime) / win32_TicksPerSecond, + User: float64(v.UserTime) / ClocksPerSec, + System: float64(v.KernelTime-v.IdleTime) / ClocksPerSec, + Idle: float64(v.IdleTime) / ClocksPerSec, + Irq: float64(v.InterruptTime) / ClocksPerSec, } ret = append(ret, c) } diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_darwin_cgo.go b/vendor/github.com/shirou/gopsutil/disk/disk_darwin_cgo.go index 623c5fda8..8a1848ed7 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_darwin_cgo.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_darwin_cgo.go @@ -7,7 +7,7 @@ package disk #cgo LDFLAGS: -framework CoreFoundation -framework IOKit #include #include -#include "disk_darwin.h" +#include "iostat_darwin.h" */ import "C" diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_windows.go b/vendor/github.com/shirou/gopsutil/disk/disk_windows.go index 02c965dda..f871e9d8c 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_windows.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_windows.go @@ -5,6 +5,8 @@ package disk import ( "bytes" "context" + "fmt" + "syscall" "unsafe" "github.com/shirou/gopsutil/internal/common" @@ -23,18 +25,24 @@ var ( FileReadOnlyVolume = int64(524288) // 0x00080000 ) -type Win32_PerfFormattedData struct { - Name string - AvgDiskBytesPerRead uint64 - AvgDiskBytesPerWrite uint64 - AvgDiskReadQueueLength uint64 - AvgDiskWriteQueueLength uint64 - AvgDisksecPerRead uint64 - AvgDisksecPerWrite uint64 +// diskPerformance is an equivalent representation of DISK_PERFORMANCE in the Windows API. +// https://docs.microsoft.com/fr-fr/windows/win32/api/winioctl/ns-winioctl-disk_performance +type diskPerformance struct { + BytesRead int64 + BytesWritten int64 + ReadTime int64 + WriteTime int64 + IdleTime int64 + ReadCount uint32 + WriteCount uint32 + QueueDepth uint32 + SplitCount uint32 + QueryTime int64 + StorageDeviceNumber uint32 + StorageManagerName [8]uint16 + alignmentPadding uint32 // necessary for 32bit support, see https://github.com/elastic/beats/pull/16553 } -const WaitMSec = 500 - func Usage(path string) (*UsageStat, error) { return UsageWithContext(context.Background(), path) } @@ -136,31 +144,52 @@ func IOCounters(names ...string) (map[string]IOCountersStat, error) { } func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { - ret := make(map[string]IOCountersStat, 0) - var dst []Win32_PerfFormattedData + // https://github.com/giampaolo/psutil/blob/544e9daa4f66a9f80d7bf6c7886d693ee42f0a13/psutil/arch/windows/disk.c#L83 + drivemap := make(map[string]IOCountersStat, 0) + var diskPerformance diskPerformance - err := common.WMIQueryWithContext(ctx, "SELECT * FROM Win32_PerfFormattedData_PerfDisk_LogicalDisk", &dst) + lpBuffer := make([]uint16, 254) + lpBufferLen, err := windows.GetLogicalDriveStrings(uint32(len(lpBuffer)), &lpBuffer[0]) if err != nil { - return ret, err + return drivemap, err } - for _, d := range dst { - if len(d.Name) > 3 { // not get _Total or Harddrive - continue - } + for _, v := range lpBuffer[:lpBufferLen] { + if 'A' <= v && v <= 'Z' { + path := string(v) + ":" + typepath, _ := windows.UTF16PtrFromString(path) + typeret := windows.GetDriveType(typepath) + if typeret == 0 { + return drivemap, windows.GetLastError() + } + if typeret != windows.DRIVE_FIXED { + continue + } + szDevice := fmt.Sprintf(`\\.\%s`, path) + const IOCTL_DISK_PERFORMANCE = 0x70020 + h, err := windows.CreateFile(syscall.StringToUTF16Ptr(szDevice), 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, 0, 0) + if err != nil { + if err == windows.ERROR_FILE_NOT_FOUND { + continue + } + return drivemap, err + } + defer windows.CloseHandle(h) - if len(names) > 0 && !common.StringsHas(names, d.Name) { - continue - } - - ret[d.Name] = IOCountersStat{ - Name: d.Name, - ReadCount: uint64(d.AvgDiskReadQueueLength), - WriteCount: d.AvgDiskWriteQueueLength, - ReadBytes: uint64(d.AvgDiskBytesPerRead), - WriteBytes: uint64(d.AvgDiskBytesPerWrite), - ReadTime: d.AvgDisksecPerRead, - WriteTime: d.AvgDisksecPerWrite, + var diskPerformanceSize uint32 + err = windows.DeviceIoControl(h, IOCTL_DISK_PERFORMANCE, nil, 0, (*byte)(unsafe.Pointer(&diskPerformance)), uint32(unsafe.Sizeof(diskPerformance)), &diskPerformanceSize, nil) + if err != nil { + return drivemap, err + } + drivemap[path] = IOCountersStat{ + ReadBytes: uint64(diskPerformance.BytesRead), + WriteBytes: uint64(diskPerformance.BytesWritten), + ReadCount: uint64(diskPerformance.ReadCount), + WriteCount: uint64(diskPerformance.WriteCount), + ReadTime: uint64(diskPerformance.ReadTime / 10000 / 1000), // convert to ms: https://github.com/giampaolo/psutil/issues/1012 + WriteTime: uint64(diskPerformance.WriteTime / 10000 / 1000), + Name: path, + } } } - return ret, nil + return drivemap, nil } diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_darwin.c b/vendor/github.com/shirou/gopsutil/disk/iostat_darwin.c similarity index 99% rename from vendor/github.com/shirou/gopsutil/disk/disk_darwin.c rename to vendor/github.com/shirou/gopsutil/disk/iostat_darwin.c index 198d3d1a7..9619c6f47 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_darwin.c +++ b/vendor/github.com/shirou/gopsutil/disk/iostat_darwin.c @@ -1,7 +1,7 @@ // https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.c #include #include -#include "disk_darwin.h" +#include "iostat_darwin.h" #define IOKIT 1 /* to get io_name_t in device_types.h */ diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_darwin.h b/vendor/github.com/shirou/gopsutil/disk/iostat_darwin.h similarity index 100% rename from vendor/github.com/shirou/gopsutil/disk/disk_darwin.h rename to vendor/github.com/shirou/gopsutil/disk/iostat_darwin.h diff --git a/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go b/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go index 283d8bdd9..9b3b1c436 100644 --- a/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go +++ b/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go @@ -4,9 +4,7 @@ package host // #cgo LDFLAGS: -framework IOKit -// #include -// #include -// #include "include/smc.c" +// #include "smc_darwin.h" import "C" import "context" diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux.go b/vendor/github.com/shirou/gopsutil/host/host_linux.go index 1ef3df6f2..6c76f905b 100644 --- a/vendor/github.com/shirou/gopsutil/host/host_linux.go +++ b/vendor/github.com/shirou/gopsutil/host/host_linux.go @@ -460,6 +460,38 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err } var warns Warnings + if len(files) == 0 { // handle distributions without hwmon, like raspbian #391, parse legacy thermal_zone files + files, err = filepath.Glob(common.HostSys("/class/thermal/thermal_zone*/")) + if err != nil { + return temperatures, err + } + for _, file := range files { + // Get the name of the temperature you are reading + name, err := ioutil.ReadFile(filepath.Join(file, "type")) + if err != nil { + warns.Add(err) + continue + } + // Get the temperature reading + current, err := ioutil.ReadFile(filepath.Join(file, "temp")) + if err != nil { + warns.Add(err) + continue + } + temperature, err := strconv.ParseInt(strings.TrimSpace(string(current)), 10, 64) + if err != nil { + warns.Add(err) + continue + } + + temperatures = append(temperatures, TemperatureStat{ + SensorKey: strings.TrimSpace(string(name)), + Temperature: float64(temperature) / 1000.0, + }) + } + return temperatures, warns.Reference() + } + // example directory // device/ temp1_crit_alarm temp2_crit_alarm temp3_crit_alarm temp4_crit_alarm temp5_crit_alarm temp6_crit_alarm temp7_crit_alarm // name temp1_input temp2_input temp3_input temp4_input temp5_input temp6_input temp7_input diff --git a/vendor/github.com/shirou/gopsutil/host/smc_darwin.c b/vendor/github.com/shirou/gopsutil/host/smc_darwin.c new file mode 100644 index 000000000..aedea8be9 --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/host/smc_darwin.c @@ -0,0 +1,170 @@ +#include +#include +#include "smc_darwin.h" + +#define IOSERVICE_SMC "AppleSMC" +#define IOSERVICE_MODEL "IOPlatformExpertDevice" + +#define DATA_TYPE_SP78 "sp78" + +typedef enum { + kSMCUserClientOpen = 0, + kSMCUserClientClose = 1, + kSMCHandleYPCEvent = 2, + kSMCReadKey = 5, + kSMCWriteKey = 6, + kSMCGetKeyCount = 7, + kSMCGetKeyFromIndex = 8, + kSMCGetKeyInfo = 9, +} selector_t; + +typedef struct { + unsigned char major; + unsigned char minor; + unsigned char build; + unsigned char reserved; + unsigned short release; +} SMCVersion; + +typedef struct { + uint16_t version; + uint16_t length; + uint32_t cpuPLimit; + uint32_t gpuPLimit; + uint32_t memPLimit; +} SMCPLimitData; + +typedef struct { + IOByteCount data_size; + uint32_t data_type; + uint8_t data_attributes; +} SMCKeyInfoData; + +typedef struct { + uint32_t key; + SMCVersion vers; + SMCPLimitData p_limit_data; + SMCKeyInfoData key_info; + uint8_t result; + uint8_t status; + uint8_t data8; + uint32_t data32; + uint8_t bytes[32]; +} SMCParamStruct; + +typedef enum { + kSMCSuccess = 0, + kSMCError = 1, + kSMCKeyNotFound = 0x84, +} kSMC_t; + +typedef struct { + uint8_t data[32]; + uint32_t data_type; + uint32_t data_size; + kSMC_t kSMC; +} smc_return_t; + +static const int SMC_KEY_SIZE = 4; // number of characters in an SMC key. +static io_connect_t conn; // our connection to the SMC. + +kern_return_t open_smc(void) { + kern_return_t result; + io_service_t service; + + service = IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching(IOSERVICE_SMC)); + if (service == 0) { + // Note: IOServiceMatching documents 0 on failure + printf("ERROR: %s NOT FOUND\n", IOSERVICE_SMC); + return kIOReturnError; + } + + result = IOServiceOpen(service, mach_task_self(), 0, &conn); + IOObjectRelease(service); + + return result; +} + +kern_return_t close_smc(void) { return IOServiceClose(conn); } + +static uint32_t to_uint32(char *key) { + uint32_t ans = 0; + uint32_t shift = 24; + + if (strlen(key) != SMC_KEY_SIZE) { + return 0; + } + + for (int i = 0; i < SMC_KEY_SIZE; i++) { + ans += key[i] << shift; + shift -= 8; + } + + return ans; +} + +static kern_return_t call_smc(SMCParamStruct *input, SMCParamStruct *output) { + kern_return_t result; + size_t input_cnt = sizeof(SMCParamStruct); + size_t output_cnt = sizeof(SMCParamStruct); + + result = IOConnectCallStructMethod(conn, kSMCHandleYPCEvent, input, input_cnt, + output, &output_cnt); + + if (result != kIOReturnSuccess) { + result = err_get_code(result); + } + return result; +} + +static kern_return_t read_smc(char *key, smc_return_t *result_smc) { + kern_return_t result; + SMCParamStruct input; + SMCParamStruct output; + + memset(&input, 0, sizeof(SMCParamStruct)); + memset(&output, 0, sizeof(SMCParamStruct)); + memset(result_smc, 0, sizeof(smc_return_t)); + + input.key = to_uint32(key); + input.data8 = kSMCGetKeyInfo; + + result = call_smc(&input, &output); + result_smc->kSMC = output.result; + + if (result != kIOReturnSuccess || output.result != kSMCSuccess) { + return result; + } + + result_smc->data_size = output.key_info.data_size; + result_smc->data_type = output.key_info.data_type; + + input.key_info.data_size = output.key_info.data_size; + input.data8 = kSMCReadKey; + + result = call_smc(&input, &output); + result_smc->kSMC = output.result; + + if (result != kIOReturnSuccess || output.result != kSMCSuccess) { + return result; + } + + memcpy(result_smc->data, output.bytes, sizeof(output.bytes)); + + return result; +} + +double get_temperature(char *key) { + kern_return_t result; + smc_return_t result_smc; + + result = read_smc(key, &result_smc); + + if (!(result == kIOReturnSuccess) && result_smc.data_size == 2 && + result_smc.data_type == to_uint32(DATA_TYPE_SP78)) { + return 0.0; + } + + return (double)result_smc.data[0]; +} diff --git a/vendor/github.com/shirou/gopsutil/host/smc_darwin.h b/vendor/github.com/shirou/gopsutil/host/smc_darwin.h new file mode 100644 index 000000000..ab51ed9f7 --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/host/smc_darwin.h @@ -0,0 +1,32 @@ +#ifndef __SMC_H__ +#define __SMC_H__ 1 + +#include + +#define AMBIENT_AIR_0 "TA0P" +#define AMBIENT_AIR_1 "TA1P" +#define CPU_0_DIODE "TC0D" +#define CPU_0_HEATSINK "TC0H" +#define CPU_0_PROXIMITY "TC0P" +#define ENCLOSURE_BASE_0 "TB0T" +#define ENCLOSURE_BASE_1 "TB1T" +#define ENCLOSURE_BASE_2 "TB2T" +#define ENCLOSURE_BASE_3 "TB3T" +#define GPU_0_DIODE "TG0D" +#define GPU_0_HEATSINK "TG0H" +#define GPU_0_PROXIMITY "TG0P" +#define HARD_DRIVE_BAY "TH0P" +#define MEMORY_SLOT_0 "TM0S" +#define MEMORY_SLOTS_PROXIMITY "TM0P" +#define NORTHBRIDGE "TN0H" +#define NORTHBRIDGE_DIODE "TN0D" +#define NORTHBRIDGE_PROXIMITY "TN0P" +#define THUNDERBOLT_0 "TI0P" +#define THUNDERBOLT_1 "TI1P" +#define WIRELESS_MODULE "TW0P" + +kern_return_t open_smc(void); +kern_return_t close_smc(void); +double get_temperature(char *); + +#endif // __SMC_H__ diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go b/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go index f558b74b3..6d0ef3713 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go @@ -10,7 +10,6 @@ import ( "path/filepath" "strconv" "strings" - "sync/atomic" "time" ) @@ -54,14 +53,7 @@ func NumProcs() (uint64, error) { return cnt, nil } -// cachedBootTime must be accessed via atomic.Load/StoreUint64 -var cachedBootTime uint64 - func BootTimeWithContext(ctx context.Context) (uint64, error) { - t := atomic.LoadUint64(&cachedBootTime) - if t != 0 { - return t, nil - } system, role, err := Virtualization() if err != nil { @@ -94,8 +86,7 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) { if err != nil { return 0, err } - t = uint64(b) - atomic.StoreUint64(&cachedBootTime, t) + t := uint64(b) return t, nil } } @@ -108,8 +99,7 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) { if err != nil { return 0, err } - t = uint64(time.Now().Unix()) - uint64(b) - atomic.StoreUint64(&cachedBootTime, t) + t := uint64(time.Now().Unix()) - uint64(b) return t, nil } diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go b/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go index dbc8b675d..9bc05ded8 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go @@ -49,21 +49,33 @@ const ( PDH_NO_DATA = 0x800007d5 ) +const ( + ProcessBasicInformation = 0 + ProcessWow64Information = 26 +) + var ( Modkernel32 = windows.NewLazySystemDLL("kernel32.dll") ModNt = windows.NewLazySystemDLL("ntdll.dll") ModPdh = windows.NewLazySystemDLL("pdh.dll") ModPsapi = windows.NewLazySystemDLL("psapi.dll") - ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes") - ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation") - PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery") - PdhAddCounter = ModPdh.NewProc("PdhAddCounterW") - PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData") - PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue") - PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery") + ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes") + ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation") + ProcRtlGetNativeSystemInformation = ModNt.NewProc("RtlGetNativeSystemInformation") + ProcRtlNtStatusToDosError = ModNt.NewProc("RtlNtStatusToDosError") + ProcNtQueryInformationProcess = ModNt.NewProc("NtQueryInformationProcess") + ProcNtReadVirtualMemory = ModNt.NewProc("NtReadVirtualMemory") + ProcNtWow64QueryInformationProcess64 = ModNt.NewProc("NtWow64QueryInformationProcess64") + ProcNtWow64ReadVirtualMemory64 = ModNt.NewProc("NtWow64ReadVirtualMemory64") - procQueryDosDeviceW = Modkernel32.NewProc("QueryDosDeviceW") + PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery") + PdhAddCounter = ModPdh.NewProc("PdhAddCounterW") + PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData") + PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue") + PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery") + + procQueryDosDeviceW = Modkernel32.NewProc("QueryDosDeviceW") ) type FILETIME struct { diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_windows.go b/vendor/github.com/shirou/gopsutil/mem/mem_windows.go index cfdf8bd1d..ced0b197d 100644 --- a/vendor/github.com/shirou/gopsutil/mem/mem_windows.go +++ b/vendor/github.com/shirou/gopsutil/mem/mem_windows.go @@ -84,7 +84,7 @@ func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { if tot == 0 { usedPercent = 0 } else { - usedPercent = float64(used) / float64(tot) + usedPercent = float64(used) / float64(tot) * 100 } ret := &SwapMemoryStat{ Total: tot, diff --git a/vendor/github.com/shirou/gopsutil/net/net.go b/vendor/github.com/shirou/gopsutil/net/net.go index c9a4bafeb..f1f99dc3a 100644 --- a/vendor/github.com/shirou/gopsutil/net/net.go +++ b/vendor/github.com/shirou/gopsutil/net/net.go @@ -3,11 +3,7 @@ package net import ( "context" "encoding/json" - "fmt" "net" - "strconv" - "strings" - "syscall" "github.com/shirou/gopsutil/internal/common" ) @@ -161,14 +157,6 @@ func (l *ConntrackStatList) Summary() []ConntrackStat { return []ConntrackStat{*summary} } -var constMap = map[string]int{ - "unix": syscall.AF_UNIX, - "TCP": syscall.SOCK_STREAM, - "UDP": syscall.SOCK_DGRAM, - "IPv4": syscall.AF_INET, - "IPv6": syscall.AF_INET6, -} - func (n IOCountersStat) String() string { s, _ := json.Marshal(n) return string(s) @@ -273,84 +261,3 @@ func getIOCountersAll(n []IOCountersStat) ([]IOCountersStat, error) { return []IOCountersStat{r}, nil } - -func parseNetLine(line string) (ConnectionStat, error) { - f := strings.Fields(line) - if len(f) < 8 { - return ConnectionStat{}, fmt.Errorf("wrong line,%s", line) - } - - if len(f) == 8 { - f = append(f, f[7]) - f[7] = "unix" - } - - pid, err := strconv.Atoi(f[1]) - if err != nil { - return ConnectionStat{}, err - } - fd, err := strconv.Atoi(strings.Trim(f[3], "u")) - if err != nil { - return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3]) - } - netFamily, ok := constMap[f[4]] - if !ok { - return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4]) - } - netType, ok := constMap[f[7]] - if !ok { - return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7]) - } - - var laddr, raddr Addr - if f[7] == "unix" { - laddr.IP = f[8] - } else { - laddr, raddr, err = parseNetAddr(f[8]) - if err != nil { - return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8]) - } - } - - n := ConnectionStat{ - Fd: uint32(fd), - Family: uint32(netFamily), - Type: uint32(netType), - Laddr: laddr, - Raddr: raddr, - Pid: int32(pid), - } - if len(f) == 10 { - n.Status = strings.Trim(f[9], "()") - } - - return n, nil -} - -func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) { - parse := func(l string) (Addr, error) { - host, port, err := net.SplitHostPort(l) - if err != nil { - return Addr{}, fmt.Errorf("wrong addr, %s", l) - } - lport, err := strconv.Atoi(port) - if err != nil { - return Addr{}, err - } - return Addr{IP: host, Port: uint32(lport)}, nil - } - - addrs := strings.Split(line, "->") - if len(addrs) == 0 { - return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line) - } - laddr, err = parse(addrs[0]) - if len(addrs) == 2 { // remote addr exists - raddr, err = parse(addrs[1]) - if err != nil { - return laddr, raddr, err - } - } - - return laddr, raddr, err -} diff --git a/vendor/github.com/shirou/gopsutil/net/net_linux.go b/vendor/github.com/shirou/gopsutil/net/net_linux.go index dc84ea83d..f289a5dcc 100644 --- a/vendor/github.com/shirou/gopsutil/net/net_linux.go +++ b/vendor/github.com/shirou/gopsutil/net/net_linux.go @@ -50,7 +50,7 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) { func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, error) { filename := common.HostProc("net/dev") - return IOCountersByFile(pernic, filename) + return IOCountersByFileWithContext(ctx, pernic, filename) } func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) { diff --git a/vendor/github.com/shirou/gopsutil/net/net_unix.go b/vendor/github.com/shirou/gopsutil/net/net_unix.go index d11fceb94..d6e4303fd 100644 --- a/vendor/github.com/shirou/gopsutil/net/net_unix.go +++ b/vendor/github.com/shirou/gopsutil/net/net_unix.go @@ -4,7 +4,11 @@ package net import ( "context" + "fmt" + "net" + "strconv" "strings" + "syscall" "github.com/shirou/gopsutil/internal/common" ) @@ -86,6 +90,95 @@ func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]C return ret, nil } +var constMap = map[string]int{ + "unix": syscall.AF_UNIX, + "TCP": syscall.SOCK_STREAM, + "UDP": syscall.SOCK_DGRAM, + "IPv4": syscall.AF_INET, + "IPv6": syscall.AF_INET6, +} + +func parseNetLine(line string) (ConnectionStat, error) { + f := strings.Fields(line) + if len(f) < 8 { + return ConnectionStat{}, fmt.Errorf("wrong line,%s", line) + } + + if len(f) == 8 { + f = append(f, f[7]) + f[7] = "unix" + } + + pid, err := strconv.Atoi(f[1]) + if err != nil { + return ConnectionStat{}, err + } + fd, err := strconv.Atoi(strings.Trim(f[3], "u")) + if err != nil { + return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3]) + } + netFamily, ok := constMap[f[4]] + if !ok { + return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4]) + } + netType, ok := constMap[f[7]] + if !ok { + return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7]) + } + + var laddr, raddr Addr + if f[7] == "unix" { + laddr.IP = f[8] + } else { + laddr, raddr, err = parseNetAddr(f[8]) + if err != nil { + return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8]) + } + } + + n := ConnectionStat{ + Fd: uint32(fd), + Family: uint32(netFamily), + Type: uint32(netType), + Laddr: laddr, + Raddr: raddr, + Pid: int32(pid), + } + if len(f) == 10 { + n.Status = strings.Trim(f[9], "()") + } + + return n, nil +} + +func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) { + parse := func(l string) (Addr, error) { + host, port, err := net.SplitHostPort(l) + if err != nil { + return Addr{}, fmt.Errorf("wrong addr, %s", l) + } + lport, err := strconv.Atoi(port) + if err != nil { + return Addr{}, err + } + return Addr{IP: host, Port: uint32(lport)}, nil + } + + addrs := strings.Split(line, "->") + if len(addrs) == 0 { + return laddr, raddr, fmt.Errorf("wrong netaddr, %s", line) + } + laddr, err = parse(addrs[0]) + if len(addrs) == 2 { // remote addr exists + raddr, err = parse(addrs[1]) + if err != nil { + return laddr, raddr, err + } + } + + return laddr, raddr, err +} + // Return up to `max` network connections opened by a process. func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error) { return ConnectionsPidMaxWithContext(context.Background(), kind, pid, max) diff --git a/vendor/github.com/shirou/gopsutil/process/process_darwin_nocgo.go b/vendor/github.com/shirou/gopsutil/process/process_darwin_nocgo.go index 86466fde5..3583e1987 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_darwin_nocgo.go +++ b/vendor/github.com/shirou/gopsutil/process/process_darwin_nocgo.go @@ -22,7 +22,7 @@ func (p *Process) ExeWithContext(ctx context.Context) (string, error) { } txtFound := 0 lines := strings.Split(string(out), "\n") - for i := 1; i < len(lines); i += 2 { + for i := 1; i < len(lines); i++ { if lines[i] == "ftxt" { txtFound++ if txtFound == 2 { diff --git a/vendor/github.com/shirou/gopsutil/process/process_linux.go b/vendor/github.com/shirou/gopsutil/process/process_linux.go index fab7b558e..afd5e28e8 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_linux.go +++ b/vendor/github.com/shirou/gopsutil/process/process_linux.go @@ -1157,10 +1157,19 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui return 0, 0, nil, 0, 0, 0, nil, err } + // There is no such thing as iotime in stat file. As an approximation, we + // will use delayacct_blkio_ticks (aggregated block I/O delays, as per Linux + // docs). Note: I am assuming at least Linux 2.6.18 + iotime, err := strconv.ParseFloat(fields[i+40], 64) + if err != nil { + iotime = 0 // Ancient linux version, most likely + } + cpuTimes := &cpu.TimesStat{ CPU: "cpu", User: float64(utime / ClockTicks), System: float64(stime / ClockTicks), + Iowait: float64(iotime / ClockTicks), } bootTime, _ := common.BootTimeWithContext(ctx) diff --git a/vendor/github.com/shirou/gopsutil/process/process_windows.go b/vendor/github.com/shirou/gopsutil/process/process_windows.go index 5dd82e383..cdce609fb 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_windows.go +++ b/vendor/github.com/shirou/gopsutil/process/process_windows.go @@ -4,14 +4,13 @@ package process import ( "context" + "errors" "fmt" "os" "strings" "syscall" - "time" "unsafe" - "github.com/StackExchange/wmi" cpu "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/internal/common" net "github.com/shirou/gopsutil/net" @@ -30,6 +29,9 @@ var ( procQueryFullProcessImageNameW = common.Modkernel32.NewProc("QueryFullProcessImageNameW") procGetPriorityClass = common.Modkernel32.NewProc("GetPriorityClass") procGetProcessIoCounters = common.Modkernel32.NewProc("GetProcessIoCounters") + procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo") + + processorArchitecture uint ) type SystemProcessInformation struct { @@ -47,6 +49,28 @@ type SystemProcessInformation struct { Reserved6 [6]uint64 } +type systemProcessorInformation struct { + ProcessorArchitecture uint16 + ProcessorLevel uint16 + ProcessorRevision uint16 + Reserved uint16 + ProcessorFeatureBits uint16 +} + +type systemInfo struct { + wProcessorArchitecture uint16 + wReserved uint16 + dwPageSize uint32 + lpMinimumApplicationAddress uintptr + lpMaximumApplicationAddress uintptr + dwActiveProcessorMask uintptr + dwNumberOfProcessors uint32 + dwProcessorType uint32 + dwAllocationGranularity uint32 + wProcessorLevel uint16 + wProcessorRevision uint16 +} + // Memory_info_ex is different between OSes type MemoryInfoExStat struct { } @@ -65,43 +89,22 @@ type ioCounters struct { OtherTransferCount uint64 } -type Win32_Process struct { - Name string - ExecutablePath *string - CommandLine *string - Priority uint32 - CreationDate *time.Time - ProcessID uint32 - ThreadCount uint32 - Status *string - ReadOperationCount uint64 - ReadTransferCount uint64 - WriteOperationCount uint64 - WriteTransferCount uint64 - CSCreationClassName string - CSName string - Caption *string - CreationClassName string - Description *string - ExecutionState *uint16 - HandleCount uint32 - KernelModeTime uint64 - MaximumWorkingSetSize *uint32 - MinimumWorkingSetSize *uint32 - OSCreationClassName string - OSName string - OtherOperationCount uint64 - OtherTransferCount uint64 - PageFaults uint32 - PageFileUsage uint32 - ParentProcessID uint32 - PeakPageFileUsage uint32 - PeakVirtualSize uint64 - PeakWorkingSetSize uint32 - PrivatePageCount uint64 - TerminationDate *time.Time - UserModeTime uint64 - WorkingSetSize uint64 +type processBasicInformation32 struct { + Reserved1 uint32 + PebBaseAddress uint32 + Reserved2 uint32 + Reserved3 uint32 + UniqueProcessId uint32 + Reserved4 uint32 +} + +type processBasicInformation64 struct { + Reserved1 uint64 + PebBaseAddress uint64 + Reserved2 uint64 + Reserved3 uint64 + UniqueProcessId uint64 + Reserved4 uint64 } type winLUID struct { @@ -125,7 +128,10 @@ type winLong int32 type winDWord uint32 func init() { - wmi.DefaultClient.AllowMissingFields = true + var systemInfo systemInfo + + procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&systemInfo))) + processorArchitecture = uint(systemInfo.wProcessorArchitecture) // enable SeDebugPrivilege https://github.com/midstar/proci/blob/6ec79f57b90ba3d9efa2a7b16ef9c9369d4be875/proci_windows.go#L80-L119 handle, err := syscall.GetCurrentProcess() @@ -237,26 +243,6 @@ func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { return ppid, nil } -func GetWin32Proc(pid int32) ([]Win32_Process, error) { - return GetWin32ProcWithContext(context.Background(), pid) -} - -func GetWin32ProcWithContext(ctx context.Context, pid int32) ([]Win32_Process, error) { - var dst []Win32_Process - query := fmt.Sprintf("WHERE ProcessId = %d", pid) - q := wmi.CreateQuery(&dst, query) - err := common.WMIQueryWithContext(ctx, q, &dst) - if err != nil { - return []Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err) - } - - if len(dst) == 0 { - return []Win32_Process{}, fmt.Errorf("could not get win32Proc: empty") - } - - return dst, nil -} - func (p *Process) Name() (string, error) { return p.NameWithContext(context.Background()) } @@ -308,12 +294,12 @@ func (p *Process) Cmdline() (string, error) { return p.CmdlineWithContext(context.Background()) } -func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { - dst, err := GetWin32ProcWithContext(ctx, p.Pid) +func (p *Process) CmdlineWithContext(_ context.Context) (string, error) { + cmdline, err := getProcessCommandLine(p.Pid) if err != nil { return "", fmt.Errorf("could not get CommandLine: %s", err) } - return *dst[0].CommandLine, nil + return cmdline, nil } // CmdlineSlice returns the command line arguments of the process as a slice with each @@ -774,24 +760,6 @@ func ProcessesWithContext(ctx context.Context) ([]*Process, error) { return out, nil } -func getProcInfo(pid int32) (*SystemProcessInformation, error) { - initialBufferSize := uint64(0x4000) - bufferSize := initialBufferSize - buffer := make([]byte, bufferSize) - - var sysProcInfo SystemProcessInformation - ret, _, _ := common.ProcNtQuerySystemInformation.Call( - uintptr(unsafe.Pointer(&sysProcInfo)), - uintptr(unsafe.Pointer(&buffer[0])), - uintptr(unsafe.Pointer(&bufferSize)), - uintptr(unsafe.Pointer(&bufferSize))) - if ret != 0 { - return nil, windows.GetLastError() - } - - return &sysProcInfo, nil -} - func getRusage(pid int32) (*windows.Rusage, error) { var CPU windows.Rusage @@ -860,3 +828,148 @@ func getProcessCPUTimes(pid int32) (SYSTEM_TIMES, error) { return times, err } + +func is32BitProcess(procHandle syscall.Handle) bool { + var wow64 uint + + ret, _, _ := common.ProcNtQueryInformationProcess.Call( + uintptr(procHandle), + uintptr(common.ProcessWow64Information), + uintptr(unsafe.Pointer(&wow64)), + uintptr(unsafe.Sizeof(wow64)), + uintptr(0), + ) + if int(ret) >= 0 { + if wow64 != 0 { + return true + } + } else { + //if the OS does not support the call, we fallback into the bitness of the app + if unsafe.Sizeof(wow64) == 4 { + return true + } + } + return false +} + +func getProcessCommandLine(pid int32) (string, error) { + h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION | windows.PROCESS_VM_READ, false, uint32(pid)) + if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER { + return "", nil + } + if err != nil { + return "", err + } + defer syscall.CloseHandle(syscall.Handle(h)) + + const ( + PROCESSOR_ARCHITECTURE_INTEL = 0 + PROCESSOR_ARCHITECTURE_ARM = 5 + PROCESSOR_ARCHITECTURE_ARM64 = 12 + PROCESSOR_ARCHITECTURE_IA64 = 6 + PROCESSOR_ARCHITECTURE_AMD64 = 9 + ) + + procIs32Bits := true + switch processorArchitecture { + case PROCESSOR_ARCHITECTURE_INTEL: + fallthrough + case PROCESSOR_ARCHITECTURE_ARM: + procIs32Bits = true + + case PROCESSOR_ARCHITECTURE_ARM64: + fallthrough + case PROCESSOR_ARCHITECTURE_IA64: + fallthrough + case PROCESSOR_ARCHITECTURE_AMD64: + procIs32Bits = is32BitProcess(syscall.Handle(h)) + + default: + //for other unknown platforms, we rely on process platform + if unsafe.Sizeof(processorArchitecture) == 8 { + procIs32Bits = false + } + } + + pebAddress := queryPebAddress(syscall.Handle(h), procIs32Bits) + if pebAddress == 0 { + return "", errors.New("cannot locate process PEB") + } + + if procIs32Bits { + buf := readProcessMemory(syscall.Handle(h), procIs32Bits, pebAddress + uint64(16), 4) + if len(buf) != 4 { + return "", errors.New("cannot locate process user parameters") + } + userProcParams := uint64(buf[0]) | (uint64(buf[1]) << 8) | (uint64(buf[2]) << 16) | (uint64(buf[3]) << 24) + + //read CommandLine field from PRTL_USER_PROCESS_PARAMETERS + remoteCmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams + uint64(64), 8) + if len(remoteCmdLine) != 8 { + return "", errors.New("cannot read cmdline field") + } + + //remoteCmdLine is actually a UNICODE_STRING32 + //the first two bytes has the length + cmdLineLength := uint(remoteCmdLine[0]) | (uint(remoteCmdLine[1]) << 8) + if cmdLineLength > 0 { + //and, at offset 4, is the pointer to the buffer + bufferAddress := uint32(remoteCmdLine[4]) | (uint32(remoteCmdLine[5]) << 8) | + (uint32(remoteCmdLine[6]) << 16) | (uint32(remoteCmdLine[7]) << 24) + + cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(bufferAddress), cmdLineLength) + if len(cmdLine) != int(cmdLineLength) { + return "", errors.New("cannot read cmdline") + } + + return convertUTF16ToString(cmdLine), nil + } + } else { + buf := readProcessMemory(syscall.Handle(h), procIs32Bits, pebAddress + uint64(32), 8) + if len(buf) != 8 { + return "", errors.New("cannot locate process user parameters") + } + userProcParams := uint64(buf[0]) | (uint64(buf[1]) << 8) | (uint64(buf[2]) << 16) | (uint64(buf[3]) << 24) | + (uint64(buf[4]) << 32) | (uint64(buf[5]) << 40) | (uint64(buf[6]) << 48) | (uint64(buf[7]) << 56) + + //read CommandLine field from PRTL_USER_PROCESS_PARAMETERS + remoteCmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams + uint64(112), 16) + if len(remoteCmdLine) != 16 { + return "", errors.New("cannot read cmdline field") + } + + //remoteCmdLine is actually a UNICODE_STRING64 + //the first two bytes has the length + cmdLineLength := uint(remoteCmdLine[0]) | (uint(remoteCmdLine[1]) << 8) + if cmdLineLength > 0 { + //and, at offset 8, is the pointer to the buffer + bufferAddress := uint64(remoteCmdLine[8]) | (uint64(remoteCmdLine[9]) << 8) | + (uint64(remoteCmdLine[10]) << 16) | (uint64(remoteCmdLine[11]) << 24) | + (uint64(remoteCmdLine[12]) << 32) | (uint64(remoteCmdLine[13]) << 40) | + (uint64(remoteCmdLine[14]) << 48) | (uint64(remoteCmdLine[15]) << 56) + + cmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, bufferAddress, cmdLineLength) + if len(cmdLine) != int(cmdLineLength) { + return "", errors.New("cannot read cmdline") + } + + return convertUTF16ToString(cmdLine), nil + } + } + + //if we reach here, we have no command line + return "", nil +} + +func convertUTF16ToString(src []byte) string { + srcLen := len(src) / 2 + + codePoints := make([]uint16, srcLen) + + srcIdx := 0 + for i := 0; i < srcLen; i++ { + codePoints[i] = uint16(src[srcIdx]) | uint16(src[srcIdx + 1] << 8) + srcIdx += 2 + } + return syscall.UTF16ToString(codePoints) +} diff --git a/vendor/github.com/shirou/gopsutil/process/process_windows_386.go b/vendor/github.com/shirou/gopsutil/process/process_windows_386.go index 68f3153dc..cd884968e 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_windows_386.go +++ b/vendor/github.com/shirou/gopsutil/process/process_windows_386.go @@ -2,6 +2,13 @@ package process +import ( + "syscall" + "unsafe" + + "github.com/shirou/gopsutil/internal/common" +) + type PROCESS_MEMORY_COUNTERS struct { CB uint32 PageFaultCount uint32 @@ -14,3 +21,82 @@ type PROCESS_MEMORY_COUNTERS struct { PagefileUsage uint32 PeakPagefileUsage uint32 } + +func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) uint64 { + if is32BitProcess { + //we are on a 32-bit process reading an external 32-bit process + var info processBasicInformation32 + + ret, _, _ := common.ProcNtQueryInformationProcess.Call( + uintptr(procHandle), + uintptr(common.ProcessBasicInformation), + uintptr(unsafe.Pointer(&info)), + uintptr(unsafe.Sizeof(info)), + uintptr(0), + ) + if int(ret) >= 0 { + return uint64(info.PebBaseAddress) + } + } else { + //we are on a 32-bit process reading an external 64-bit process + if common.ProcNtWow64QueryInformationProcess64.Find() == nil { //avoid panic + var info processBasicInformation64 + + ret, _, _ := common.ProcNtWow64QueryInformationProcess64.Call( + uintptr(procHandle), + uintptr(common.ProcessBasicInformation), + uintptr(unsafe.Pointer(&info)), + uintptr(unsafe.Sizeof(info)), + uintptr(0), + ) + if int(ret) >= 0 { + return info.PebBaseAddress + } + } + } + + //return 0 on error + return 0 +} + +func readProcessMemory(h syscall.Handle, is32BitProcess bool, address uint64, size uint) []byte { + if is32BitProcess { + var read uint + + buffer := make([]byte, size) + + ret, _, _ := common.ProcNtReadVirtualMemory.Call( + uintptr(h), + uintptr(address), + uintptr(unsafe.Pointer(&buffer[0])), + uintptr(size), + uintptr(unsafe.Pointer(&read)), + ) + if int(ret) >= 0 && read > 0 { + return buffer[:read] + } + } else { + //reading a 64-bit process from a 32-bit one + if common.ProcNtWow64ReadVirtualMemory64.Find() == nil { //avoid panic + var read uint64 + + buffer := make([]byte, size) + + ret, _, _ := common.ProcNtWow64ReadVirtualMemory64.Call( + uintptr(h), + uintptr(address & 0xFFFFFFFF), //the call expects a 64-bit value + uintptr(address >> 32), + uintptr(unsafe.Pointer(&buffer[0])), + uintptr(size), //the call expects a 64-bit value + uintptr(0), //but size is 32-bit so pass zero as the high dword + uintptr(unsafe.Pointer(&read)), + ) + if int(ret) >= 0 && read > 0 { + return buffer[:uint(read)] + } + } + } + + //if we reach here, an error happened + return nil +} diff --git a/vendor/github.com/shirou/gopsutil/process/process_windows_amd64.go b/vendor/github.com/shirou/gopsutil/process/process_windows_amd64.go index df286dfff..3ee5be449 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_windows_amd64.go +++ b/vendor/github.com/shirou/gopsutil/process/process_windows_amd64.go @@ -2,6 +2,13 @@ package process +import ( + "syscall" + "unsafe" + + "github.com/shirou/gopsutil/internal/common" +) + type PROCESS_MEMORY_COUNTERS struct { CB uint32 PageFaultCount uint32 @@ -14,3 +21,56 @@ type PROCESS_MEMORY_COUNTERS struct { PagefileUsage uint64 PeakPagefileUsage uint64 } + +func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) uint64 { + if is32BitProcess { + //we are on a 64-bit process reading an external 32-bit process + var wow64 uint + + ret, _, _ := common.ProcNtQueryInformationProcess.Call( + uintptr(procHandle), + uintptr(common.ProcessWow64Information), + uintptr(unsafe.Pointer(&wow64)), + uintptr(unsafe.Sizeof(wow64)), + uintptr(0), + ) + if int(ret) >= 0 { + return uint64(wow64) + } + } else { + //we are on a 64-bit process reading an external 64-bit process + var info processBasicInformation64 + + ret, _, _ := common.ProcNtQueryInformationProcess.Call( + uintptr(procHandle), + uintptr(common.ProcessBasicInformation), + uintptr(unsafe.Pointer(&info)), + uintptr(unsafe.Sizeof(info)), + uintptr(0), + ) + if int(ret) >= 0 { + return info.PebBaseAddress + } + } + + //return 0 on error + return 0 +} + +func readProcessMemory(procHandle syscall.Handle, _ bool, address uint64, size uint) []byte { + var read uint + + buffer := make([]byte, size) + + ret, _, _ := common.ProcNtReadVirtualMemory.Call( + uintptr(procHandle), + uintptr(address), + uintptr(unsafe.Pointer(&buffer[0])), + uintptr(size), + uintptr(unsafe.Pointer(&read)), + ) + if int(ret) >= 0 && read > 0 { + return buffer[:read] + } + return nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 73efb9e71..07187680e 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -700,7 +700,7 @@ github.com/sean-/seed # github.com/seccomp/libseccomp-golang v0.9.2-0.20200314001724-bdab42bd5128 ## explicit github.com/seccomp/libseccomp-golang -# github.com/shirou/gopsutil v2.20.2+incompatible +# github.com/shirou/gopsutil v2.20.2+incompatible => github.com/hashicorp/gopsutil v2.18.13-0.20200531184148-5aca383d4f9d+incompatible ## explicit github.com/shirou/gopsutil/cpu github.com/shirou/gopsutil/disk @@ -1059,3 +1059,4 @@ honnef.co/go/tools/version # github.com/godbus/dbus => github.com/godbus/dbus v5.0.1+incompatible # github.com/hashicorp/nomad/api => ./api # github.com/kr/pty => github.com/kr/pty v1.1.5 +# github.com/shirou/gopsutil => github.com/hashicorp/gopsutil v2.18.13-0.20200531184148-5aca383d4f9d+incompatible