From 84570dfed13556828035d44bd505b1cd24da3838 Mon Sep 17 00:00:00 2001 From: Caleb Bassi Date: Tue, 15 May 2018 11:16:16 -0700 Subject: [PATCH 1/4] Update gopsutil --- Gopkg.lock | 2 +- vendor/github.com/shirou/gopsutil/README.rst | 4 + .../github.com/shirou/gopsutil/disk/disk.go | 1 + .../shirou/gopsutil/disk/disk_linux.go | 23 + .../shirou/gopsutil/host/host_darwin.go | 8 + .../shirou/gopsutil/host/host_darwin_cgo.go | 51 -- .../shirou/gopsutil/host/host_darwin_nocgo.go | 18 - .../gopsutil/host/host_linux_mips64le.go | 43 ++ .../shirou/gopsutil/host/include/smc.c | 700 ------------------ .../shirou/gopsutil/host/include/smc.h | 254 ------- .../shirou/gopsutil/mem/mem_freebsd.go | 2 +- 11 files changed, 81 insertions(+), 1025 deletions(-) delete mode 100644 vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go delete mode 100644 vendor/github.com/shirou/gopsutil/host/host_darwin_nocgo.go create mode 100644 vendor/github.com/shirou/gopsutil/host/host_linux_mips64le.go delete mode 100644 vendor/github.com/shirou/gopsutil/host/include/smc.c delete mode 100644 vendor/github.com/shirou/gopsutil/host/include/smc.h diff --git a/Gopkg.lock b/Gopkg.lock index 0cc5818..0407209 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -58,7 +58,7 @@ "net", "process" ] - revision = "cd915bdc31582b0a56405ede7fa2f4ab043f851b" + revision = "57f370e13068146efe1cb7129f79e5d51da8a242" [[projects]] branch = "master" diff --git a/vendor/github.com/shirou/gopsutil/README.rst b/vendor/github.com/shirou/gopsutil/README.rst index bc4614f..9848aec 100644 --- a/vendor/github.com/shirou/gopsutil/README.rst +++ b/vendor/github.com/shirou/gopsutil/README.rst @@ -117,6 +117,10 @@ Several methods have been added which are not present in psutil, but will provid - VirtualizationSystem (ex: "LXC") - VirtualizationRole (ex: "guest"/"host") +- IOCounters + + - Label (linux only) The registered [device mapper name](https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block-dm) + - cpu/CPUInfo() (linux, freebsd) - CPU (ex: 0, 1, ...) diff --git a/vendor/github.com/shirou/gopsutil/disk/disk.go b/vendor/github.com/shirou/gopsutil/disk/disk.go index 1c31047..38d8a8f 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk.go @@ -42,6 +42,7 @@ type IOCountersStat struct { WeightedIO uint64 `json:"weightedIO"` Name string `json:"name"` SerialNumber string `json:"serialNumber"` + Label string `json:"label"` } func (d UsageStat) String() string { diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_linux.go b/vendor/github.com/shirou/gopsutil/disk/disk_linux.go index 46904e3..4033b1a 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_linux.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_linux.go @@ -5,6 +5,7 @@ package disk import ( "context" "fmt" + "io/ioutil" "os/exec" "path/filepath" "strconv" @@ -370,6 +371,8 @@ func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOC d.Name = name d.SerialNumber = GetDiskSerialNumber(name) + d.Label = GetLabel(name) + ret[name] = d } return ret, nil @@ -406,6 +409,26 @@ func GetDiskSerialNumberWithContext(ctx context.Context, name string) string { return "" } +// GetLabel returns label of given device or empty string on error. +// Name of device is expected, eg. /dev/sda +// Supports label based on devicemapper name +// See https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-block-dm +func GetLabel(name string) string { + // Try label based on devicemapper name + dmname_filename := common.HostSys(fmt.Sprintf("block/%s/dm/name", name)) + + if !common.PathExists(dmname_filename) { + return "" + } + + dmname, err := ioutil.ReadFile(dmname_filename) + if err != nil { + return "" + } else { + return string(dmname) + } +} + func getFsType(stat unix.Statfs_t) string { t := int64(stat.Type) ret, ok := fsTypeMap[t] diff --git a/vendor/github.com/shirou/gopsutil/host/host_darwin.go b/vendor/github.com/shirou/gopsutil/host/host_darwin.go index acefc2f..5a4066a 100644 --- a/vendor/github.com/shirou/gopsutil/host/host_darwin.go +++ b/vendor/github.com/shirou/gopsutil/host/host_darwin.go @@ -217,3 +217,11 @@ func KernelVersionWithContext(ctx context.Context) (string, error) { _, _, version, err := PlatformInformation() return version, err } + +func SensorsTemperatures() ([]TemperatureStat, error) { + return SensorsTemperaturesWithContext(context.Background()) +} + +func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { + return []TemperatureStat{}, common.ErrNotImplementedError +} diff --git a/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go b/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go deleted file mode 100644 index f0a4370..0000000 --- a/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go +++ /dev/null @@ -1,51 +0,0 @@ -// +build darwin -// +build cgo - -package host - -// #cgo LDFLAGS: -framework IOKit -// #include "include/smc.c" -import "C" -import "context" - -func SensorsTemperatures() ([]TemperatureStat, error) { - return SensorsTemperaturesWithContext(context.Background()) -} - -func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { - temperatureKeys := []string{ - C.AMBIENT_AIR_0, - C.AMBIENT_AIR_1, - C.CPU_0_DIODE, - C.CPU_0_HEATSINK, - C.CPU_0_PROXIMITY, - C.ENCLOSURE_BASE_0, - C.ENCLOSURE_BASE_1, - C.ENCLOSURE_BASE_2, - C.ENCLOSURE_BASE_3, - C.GPU_0_DIODE, - C.GPU_0_HEATSINK, - C.GPU_0_PROXIMITY, - C.HARD_DRIVE_BAY, - C.MEMORY_SLOT_0, - C.MEMORY_SLOTS_PROXIMITY, - C.NORTHBRIDGE, - C.NORTHBRIDGE_DIODE, - C.NORTHBRIDGE_PROXIMITY, - C.THUNDERBOLT_0, - C.THUNDERBOLT_1, - C.WIRELESS_MODULE, - } - var temperatures []TemperatureStat - - C.open_smc() - defer C.close_smc() - - for _, key := range temperatureKeys { - temperatures = append(temperatures, TemperatureStat{ - SensorKey: key, - Temperature: float64(C.get_tmp(C.CString(key), C.CELSIUS)), - }) - } - return temperatures, nil -} diff --git a/vendor/github.com/shirou/gopsutil/host/host_darwin_nocgo.go b/vendor/github.com/shirou/gopsutil/host/host_darwin_nocgo.go deleted file mode 100644 index 7869f8c..0000000 --- a/vendor/github.com/shirou/gopsutil/host/host_darwin_nocgo.go +++ /dev/null @@ -1,18 +0,0 @@ -// +build darwin -// +build !cgo - -package host - -import ( - "context" - - "github.com/shirou/gopsutil/internal/common" -) - -func SensorsTemperatures() ([]TemperatureStat, error) { - return SensorsTemperaturesWithContext(context.Background()) -} - -func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) { - return []TemperatureStat{}, common.ErrNotImplementedError -} diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux_mips64le.go b/vendor/github.com/shirou/gopsutil/host/host_linux_mips64le.go new file mode 100644 index 0000000..b0fca09 --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/host/host_linux_mips64le.go @@ -0,0 +1,43 @@ +// Created by cgo -godefs - DO NOT EDIT +// cgo -godefs types_linux.go + +package host + +const ( + sizeofPtr = 0x4 + sizeofShort = 0x2 + sizeofInt = 0x4 + sizeofLong = 0x4 + sizeofLongLong = 0x8 + sizeOfUtmp = 0x180 +) + +type ( + _C_short int16 + _C_int int32 + _C_long int32 + _C_long_long int64 +) + +type utmp struct { + Type int16 + Pad_cgo_0 [2]byte + Pid int32 + Line [32]int8 + Id [4]int8 + User [32]int8 + Host [256]int8 + Exit exit_status + Session int32 + Tv timeval + Addr_v6 [4]int32 + X__unused [20]int8 +} +type exit_status struct { + Termination int16 + Exit int16 +} +type timeval struct { + Sec int32 + Usec int32 +} diff --git a/vendor/github.com/shirou/gopsutil/host/include/smc.c b/vendor/github.com/shirou/gopsutil/host/include/smc.c deleted file mode 100644 index 30a232b..0000000 --- a/vendor/github.com/shirou/gopsutil/host/include/smc.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Apple System Management Controller (SMC) API from user space for Intel based - * Macs. Works by talking to the AppleSMC.kext (kernel extension), the driver - * for the SMC. - * - * smc.c - * libsmc - * - * Copyright (C) 2014 beltex - * - * Based off of fork from: - * osx-cpu-temp - * - * With credits to: - * - * Copyright (C) 2006 devnull - * Apple System Management Control (SMC) Tool - * - * Copyright (C) 2006 Hendrik Holtmann - * smcFanControl - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include "smc.h" - - -//------------------------------------------------------------------------------ -// MARK: MACROS -//------------------------------------------------------------------------------ - - -/** -Name of the SMC IOService as seen in the IORegistry. You can view it either via -command line with ioreg or through the IORegistryExplorer app (found on Apple's -developer site - Hardware IO Tools for Xcode) -*/ -#define IOSERVICE_SMC "AppleSMC" - - -/** -IOService for getting machine model name -*/ -#define IOSERVICE_MODEL "IOPlatformExpertDevice" - - -/** -SMC data types - 4 byte multi-character constants - -Sources: See TMP SMC keys in smc.h - -http://stackoverflow.com/questions/22160746/fpe2-and-sp78-data-types -*/ -#define DATA_TYPE_UINT8 "ui8 " -#define DATA_TYPE_UINT16 "ui16" -#define DATA_TYPE_UINT32 "ui32" -#define DATA_TYPE_FLAG "flag" -#define DATA_TYPE_FPE2 "fpe2" -#define DATA_TYPE_SFDS "{fds" -#define DATA_TYPE_SP78 "sp78" - - -//------------------------------------------------------------------------------ -// MARK: GLOBAL VARS -//------------------------------------------------------------------------------ - - -/** -Our connection to the SMC -*/ -static io_connect_t conn; - - -/** -Number of characters in an SMC key -*/ -static const int SMC_KEY_SIZE = 4; - - -/** -Number of characters in a data type "key" returned from the SMC. See data type -macros. -*/ -static const int DATA_TYPE_SIZE = 4; - - -//------------------------------------------------------------------------------ -// MARK: ENUMS -//------------------------------------------------------------------------------ - - -/** -Defined by AppleSMC.kext. See SMCParamStruct. - -These are SMC specific return codes -*/ -typedef enum { - kSMCSuccess = 0, - kSMCError = 1, - kSMCKeyNotFound = 0x84 -} kSMC_t; - - -/** -Defined by AppleSMC.kext. See SMCParamStruct. - -Function selectors. Used to tell the SMC which function inside it to call. -*/ -typedef enum { - kSMCUserClientOpen = 0, - kSMCUserClientClose = 1, - kSMCHandleYPCEvent = 2, - kSMCReadKey = 5, - kSMCWriteKey = 6, - kSMCGetKeyCount = 7, - kSMCGetKeyFromIndex = 8, - kSMCGetKeyInfo = 9 -} selector_t; - - -//------------------------------------------------------------------------------ -// MARK: STRUCTS -//------------------------------------------------------------------------------ - - -/** -Defined by AppleSMC.kext. See SMCParamStruct. -*/ -typedef struct { - unsigned char major; - unsigned char minor; - unsigned char build; - unsigned char reserved; - unsigned short release; -} SMCVersion; - - -/** -Defined by AppleSMC.kext. See SMCParamStruct. -*/ -typedef struct { - uint16_t version; - uint16_t length; - uint32_t cpuPLimit; - uint32_t gpuPLimit; - uint32_t memPLimit; -} SMCPLimitData; - - -/** -Defined by AppleSMC.kext. See SMCParamStruct. - -- dataSize : How many values written to SMCParamStruct.bytes -- dataType : Type of data written to SMCParamStruct.bytes. This lets us know how - to interpret it (translate it to human readable) -*/ -typedef struct { - IOByteCount dataSize; - uint32_t dataType; - uint8_t dataAttributes; -} SMCKeyInfoData; - - -/** -Defined by AppleSMC.kext. - -This is the predefined struct that must be passed to communicate with the -AppleSMC driver. While the driver is closed source, the definition of this -struct happened to appear in the Apple PowerManagement project at around -version 211, and soon after disappeared. It can be seen in the PrivateLib.c -file under pmconfigd. - -https://www.opensource.apple.com/source/PowerManagement/PowerManagement-211/ -*/ -typedef struct { - uint32_t key; - SMCVersion vers; - SMCPLimitData pLimitData; - SMCKeyInfoData keyInfo; - uint8_t result; - uint8_t status; - uint8_t data8; - uint32_t data32; - uint8_t bytes[32]; -} SMCParamStruct; - - -/** -Used for returning data from the SMC. -*/ -typedef struct { - uint8_t data[32]; - uint32_t dataType; - uint32_t dataSize; - kSMC_t kSMC; -} smc_return_t; - - -//------------------------------------------------------------------------------ -// MARK: HELPERS - TYPE CONVERSION -//------------------------------------------------------------------------------ - - -/** -Convert data from SMC of fpe2 type to human readable. - -:param: data Data from the SMC to be converted. Assumed data size of 2. -:returns: Converted data -*/ -static unsigned int from_fpe2(uint8_t data[32]) -{ - unsigned int ans = 0; - - // Data type for fan calls - fpe2 - // This is assumend to mean floating point, with 2 exponent bits - // http://stackoverflow.com/questions/22160746/fpe2-and-sp78-data-types - ans += data[0] << 6; - ans += data[1] << 2; - - return ans; -} - - -/** -Convert to fpe2 data type to be passed to SMC. - -:param: val Value to convert -:param: data Pointer to data array to place result -*/ -static void to_fpe2(unsigned int val, uint8_t *data) -{ - data[0] = val >> 6; - data[1] = (val << 2) ^ (data[0] << 8); -} - - -/** -Convert SMC key to uint32_t. This must be done to pass it to the SMC. - -:param: key The SMC key to convert -:returns: uint32_t translation. - Returns zero if key is not 4 characters in length. -*/ -static uint32_t to_uint32_t(char *key) -{ - uint32_t ans = 0; - uint32_t shift = 24; - - // SMC key is expected to be 4 bytes - thus 4 chars - 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; -} - - -/** -For converting the dataType return from the SMC to human readable 4 byte -multi-character constant. -*/ -static void to_string(uint32_t val, char *dataType) -{ - int shift = 24; - - for (int i = 0; i < DATA_TYPE_SIZE; i++) { - // To get each char, we shift it into the lower 8 bits, and then & by - // 255 to insolate it - dataType[i] = (val >> shift) & 0xff; - shift -= 8; - } -} - - -//------------------------------------------------------------------------------ -// MARK: HELPERS - TMP CONVERSION -//------------------------------------------------------------------------------ - - -/** -Celsius to Fahrenheit -*/ -static double to_fahrenheit(double tmp) -{ - // http://en.wikipedia.org/wiki/Fahrenheit#Definition_and_conversions - return (tmp * 1.8) + 32; -} - - -/** -Celsius to Kelvin -*/ -static double to_kelvin(double tmp) -{ - // http://en.wikipedia.org/wiki/Kelvin - return tmp + 273.15; -} - - -//------------------------------------------------------------------------------ -// MARK: "PRIVATE" FUNCTIONS -//------------------------------------------------------------------------------ - - -/** -Make a call to the SMC - -:param: inputStruct Struct that holds data telling the SMC what you want -:param: outputStruct Struct holding the SMC's response -:returns: I/O Kit return code -*/ -static kern_return_t call_smc(SMCParamStruct *inputStruct, - SMCParamStruct *outputStruct) -{ - kern_return_t result; - size_t inputStructCnt = sizeof(SMCParamStruct); - size_t outputStructCnt = sizeof(SMCParamStruct); - - result = IOConnectCallStructMethod(conn, kSMCHandleYPCEvent, - inputStruct, - inputStructCnt, - outputStruct, - &outputStructCnt); - - if (result != kIOReturnSuccess) { - // IOReturn error code lookup. See "Accessing Hardware From Applications - // -> Handling Errors" Apple doc - result = err_get_code(result); - } - - return result; -} - - -/** -Read data from the SMC - -:param: key The SMC key -*/ -static kern_return_t read_smc(char *key, smc_return_t *result_smc) -{ - kern_return_t result; - SMCParamStruct inputStruct; - SMCParamStruct outputStruct; - - memset(&inputStruct, 0, sizeof(SMCParamStruct)); - memset(&outputStruct, 0, sizeof(SMCParamStruct)); - memset(result_smc, 0, sizeof(smc_return_t)); - - // First call to AppleSMC - get key info - inputStruct.key = to_uint32_t(key); - inputStruct.data8 = kSMCGetKeyInfo; - - result = call_smc(&inputStruct, &outputStruct); - result_smc->kSMC = outputStruct.result; - - if (result != kIOReturnSuccess || outputStruct.result != kSMCSuccess) { - return result; - } - - // Store data for return - result_smc->dataSize = outputStruct.keyInfo.dataSize; - result_smc->dataType = outputStruct.keyInfo.dataType; - - - // Second call to AppleSMC - now we can get the data - inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize; - inputStruct.data8 = kSMCReadKey; - - result = call_smc(&inputStruct, &outputStruct); - result_smc->kSMC = outputStruct.result; - - if (result != kIOReturnSuccess || outputStruct.result != kSMCSuccess) { - return result; - } - - memcpy(result_smc->data, outputStruct.bytes, sizeof(outputStruct.bytes)); - - return result; -} - - -/** -Write data to the SMC. - -:returns: IOReturn IOKit return code -*/ -static kern_return_t write_smc(char *key, smc_return_t *result_smc) -{ - kern_return_t result; - SMCParamStruct inputStruct; - SMCParamStruct outputStruct; - - memset(&inputStruct, 0, sizeof(SMCParamStruct)); - memset(&outputStruct, 0, sizeof(SMCParamStruct)); - - // First call to AppleSMC - get key info - inputStruct.key = to_uint32_t(key); - inputStruct.data8 = kSMCGetKeyInfo; - - result = call_smc(&inputStruct, &outputStruct); - result_smc->kSMC = outputStruct.result; - - if (result != kIOReturnSuccess || outputStruct.result != kSMCSuccess) { - return result; - } - - // Check data is correct - if (result_smc->dataSize != outputStruct.keyInfo.dataSize || - result_smc->dataType != outputStruct.keyInfo.dataType) { - return kIOReturnBadArgument; - } - - // Second call to AppleSMC - now we can write the data - inputStruct.data8 = kSMCWriteKey; - inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize; - - // Set data to write - memcpy(inputStruct.bytes, result_smc->data, sizeof(result_smc->data)); - - result = call_smc(&inputStruct, &outputStruct); - result_smc->kSMC = outputStruct.result; - - return result; -} - - -/** -Get the model name of the machine. -*/ -static kern_return_t get_machine_model(io_name_t model) -{ - io_service_t service; - kern_return_t result; - - service = IOServiceGetMatchingService(kIOMasterPortDefault, - IOServiceMatching(IOSERVICE_MODEL)); - - if (service == 0) { - printf("ERROR: %s NOT FOUND\n", IOSERVICE_MODEL); - return kIOReturnError; - } - - // Get the model name - result = IORegistryEntryGetName(service, model); - IOObjectRelease(service); - - return result; -} - - -//------------------------------------------------------------------------------ -// MARK: "PUBLIC" FUNCTIONS -//------------------------------------------------------------------------------ - - -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); -} - - -bool is_key_valid(char *key) -{ - bool ans = false; - kern_return_t result; - smc_return_t result_smc; - - if (strlen(key) != SMC_KEY_SIZE) { - printf("ERROR: Invalid key size - must be 4 chars\n"); - return ans; - } - - // Try a read and see if it succeeds - result = read_smc(key, &result_smc); - - if (result == kIOReturnSuccess && result_smc.kSMC == kSMCSuccess) { - ans = true; - } - - return ans; -} - - -double get_tmp(char *key, tmp_unit_t unit) -{ - kern_return_t result; - smc_return_t result_smc; - - result = read_smc(key, &result_smc); - - if (!(result == kIOReturnSuccess && - result_smc.dataSize == 2 && - result_smc.dataType == to_uint32_t(DATA_TYPE_SP78))) { - // Error - return 0.0; - } - - // TODO: Create from_sp78() convert function - double tmp = result_smc.data[0]; - - switch (unit) { - case CELSIUS: - break; - case FAHRENHEIT: - tmp = to_fahrenheit(tmp); - break; - case KELVIN: - tmp = to_kelvin(tmp); - break; - } - - return tmp; -} - - -bool is_battery_powered(void) -{ - kern_return_t result; - smc_return_t result_smc; - - result = read_smc(BATT_PWR, &result_smc); - - if (!(result == kIOReturnSuccess && - result_smc.dataSize == 1 && - result_smc.dataType == to_uint32_t(DATA_TYPE_FLAG))) { - // Error - return false; - } - - return result_smc.data[0]; -} - - -bool is_optical_disk_drive_full(void) -{ - kern_return_t result; - smc_return_t result_smc; - - result = read_smc(ODD_FULL, &result_smc); - - if (!(result == kIOReturnSuccess && - result_smc.dataSize == 1 && - result_smc.dataType == to_uint32_t(DATA_TYPE_FLAG))) { - // Error - return false; - } - - return result_smc.data[0]; -} - - -//------------------------------------------------------------------------------ -// MARK: FAN FUNCTIONS -//------------------------------------------------------------------------------ - - -bool get_fan_name(unsigned int fan_num, fan_name_t name) -{ - char key[5]; - kern_return_t result; - smc_return_t result_smc; - - sprintf(key, "F%dID", fan_num); - result = read_smc(key, &result_smc); - - if (!(result == kIOReturnSuccess && - result_smc.dataSize == 16 && - result_smc.dataType == to_uint32_t(DATA_TYPE_SFDS))) { - return false; - } - - - /* - We know the data size is 16 bytes and the type is "{fds", a custom - struct defined by the AppleSMC.kext. See TMP enum sources for the - struct. - - The last 12 bytes contain the name of the fan, an array of chars, hence - the loop range. - */ - int index = 0; - for (int i = 4; i < 16; i++) { - // Check if at the end (name may not be full 12 bytes) - // Could check for 0 (null), but instead we check for 32 (space). This - // is a hack to remove whitespace. :) - if (result_smc.data[i] == 32) { - break; - } - - name[index] = result_smc.data[i]; - index++; - } - - return true; -} - - -int get_num_fans(void) -{ - kern_return_t result; - smc_return_t result_smc; - - result = read_smc(NUM_FANS, &result_smc); - - if (!(result == kIOReturnSuccess && - result_smc.dataSize == 1 && - result_smc.dataType == to_uint32_t(DATA_TYPE_UINT8))) { - // Error - return -1; - } - - return result_smc.data[0]; -} - - -unsigned int get_fan_rpm(unsigned int fan_num) -{ - char key[5]; - kern_return_t result; - smc_return_t result_smc; - - sprintf(key, "F%dAc", fan_num); - result = read_smc(key, &result_smc); - - if (!(result == kIOReturnSuccess && - result_smc.dataSize == 2 && - result_smc.dataType == to_uint32_t(DATA_TYPE_FPE2))) { - // Error - return 0; - } - - return from_fpe2(result_smc.data); -} - - -bool set_fan_min_rpm(unsigned int fan_num, unsigned int rpm, bool auth) -{ - // TODO: Add rpm val safety check - char key[5]; - bool ans = false; - kern_return_t result; - smc_return_t result_smc; - - memset(&result_smc, 0, sizeof(smc_return_t)); - - // TODO: Don't use magic number - result_smc.dataSize = 2; - result_smc.dataType = to_uint32_t(DATA_TYPE_FPE2); - to_fpe2(rpm, result_smc.data); - - sprintf(key, "F%dMn", fan_num); - result = write_smc(key, &result_smc); - - if (result == kIOReturnSuccess && result_smc.kSMC == kSMCSuccess) { - ans = true; - } - - return ans; -} diff --git a/vendor/github.com/shirou/gopsutil/host/include/smc.h b/vendor/github.com/shirou/gopsutil/host/include/smc.h deleted file mode 100644 index b156368..0000000 --- a/vendor/github.com/shirou/gopsutil/host/include/smc.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Apple System Management Controller (SMC) API from user space for Intel based - * Macs. Works by talking to the AppleSMC.kext (kernel extension), the driver - * for the SMC. - * - * smc.h - * libsmc - * - * Copyright (C) 2014 beltex - * - * Based off of fork from: - * osx-cpu-temp - * - * With credits to: - * - * Copyright (C) 2006 devnull - * Apple System Management Control (SMC) Tool - * - * Copyright (C) 2006 Hendrik Holtmann - * smcFanControl - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include - - -//------------------------------------------------------------------------------ -// MARK: MACROS -//------------------------------------------------------------------------------ - - -/** -SMC keys for temperature sensors - 4 byte multi-character constants - -Not applicable to all Mac's of course. In adition, the definition of the codes -may not be 100% accurate necessarily. Finally, list is incomplete. - -Presumed letter translations: - -- T = Temperature (if first char) -- C = CPU -- G = GPU -- P = Proximity -- D = Diode -- H = Heatsink - -Sources: - -- https://www.apple.com/downloads/dashboard/status/istatpro.html -- https://github.com/hholtmann/smcFanControl -- https://github.com/jedda/OSX-Monitoring-Tools -- http://www.parhelia.ch/blog/statics/k3_keys.html -*/ -#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" - - -/** -SMC keys for fans - 4 byte multi-character constants - -Number of fans on Macs vary of course, thus not all keys will be applicable. - -Presumed letter translations: - -- F = Fan -- Ac = Acutal -- Mn = Min -- Mx = Max -- Sf = Safe -- Tg = Target - -Sources: See TMP SMC keys -*/ -#define FAN_0 "F0Ac" -#define FAN_0_MIN_RPM "F0Mn" -#define FAN_0_MAX_RPM "F0Mx" -#define FAN_0_SAFE_RPM "F0Sf" -#define FAN_0_TARGET_RPM "F0Tg" -#define FAN_1 "F1Ac" -#define FAN_1_MIN_RPM "F1Mn" -#define FAN_1_MAX_RPM "F1Mx" -#define FAN_1_SAFE_RPM "F1Sf" -#define FAN_1_TARGET_RPM "F1Tg" -#define FAN_2 "F2Ac" -#define FAN_2_MIN_RPM "F2Mn" -#define FAN_2_MAX_RPM "F2Mx" -#define FAN_2_SAFE_RPM "F2Sf" -#define FAN_2_TARGET_RPM "F2Tg" -#define NUM_FANS "FNum" -#define FORCE_BITS "FS! " - - -/** -Misc SMC keys - 4 byte multi-character constants - -Sources: See TMP SMC keys -*/ -#define BATT_PWR "BATP" -#define NUM_KEYS "#KEY" -#define ODD_FULL "MSDI" - - -//------------------------------------------------------------------------------ -// MARK: TYPES -//------------------------------------------------------------------------------ - - -typedef char fan_name_t[13]; - - -//------------------------------------------------------------------------------ -// MARK: ENUMS -//------------------------------------------------------------------------------ - - -typedef enum { - CELSIUS, - FAHRENHEIT, - KELVIN -} tmp_unit_t; - - -//------------------------------------------------------------------------------ -// MARK: PROTOTYPES -//------------------------------------------------------------------------------ - - -/** -Open a connection to the SMC - -:returns: kIOReturnSuccess on successful connection to the SMC. -*/ -kern_return_t open_smc(void); - - -/** -Close connection to the SMC - -:returns: kIOReturnSuccess on successful close of connection to the SMC. -*/ -kern_return_t close_smc(void); - - -/** -Check if an SMC key is valid. Useful for determining if a certain machine has -particular sensor or fan for example. - -:param: key The SMC key to check. 4 byte multi-character constant. Must be 4 - characters in length. -:returns: True if the key is found, false otherwise -*/ -bool is_key_valid(char *key); - - -/** -Get the current temperature from a sensor - -:param: key The temperature sensor to read from -:param: unit The unit for the temperature value. -:returns: Temperature of sensor. If the sensor is not found, or an error - occurs, return will be zero -*/ -double get_tmp(char *key, tmp_unit_t unit); - - -/** -Is the machine being powered by the battery? - -:returns: True if it is, false otherwise -*/ -bool is_battery_powered(void); - - -/** -Is there a CD in the optical disk drive (ODD)? - -:returns: True if there is, false otherwise -*/ -bool is_optical_disk_drive_full(void); - - -/** -Get the name of a fan. - -:param: fanNum The number of the fan to check -:param: name The name of the fan. Return will be empty on error. -:returns: True if successful, false otherwise. -*/ -bool get_fan_name(unsigned int fan_num, fan_name_t name); - - -/** -Get the number of fans on this machine. - -:returns: The number of fans. If an error occurs, return will be -1. -*/ -int get_num_fans(void); - - -/** -Get the current speed (RPM - revolutions per minute) of a fan. - -:param: fan_num The number of the fan to check -:returns: The fan RPM. If the fan is not found, or an error occurs, return - will be zero -*/ -UInt get_fan_rpm(UInt fan_num); - - -/** -Set the minimum speed (RPM - revolutions per minute) of a fan. This method -requires root privileges. By minimum we mean that OS X can interject and -raise the fan speed if needed, however it will not go below this. - -WARNING: You are playing with hardware here, BE CAREFUL. - -:param: fan_num The number of the fan to set -:param: rpm The speed you would like to set the fan to. -:param: auth Should the function do authentication? -:return: True if successful, false otherwise -*/ -bool set_fan_min_rpm(unsigned int fan_num, unsigned int rpm, bool auth); diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_freebsd.go b/vendor/github.com/shirou/gopsutil/mem/mem_freebsd.go index 1fa880b..2d65f80 100644 --- a/vendor/github.com/shirou/gopsutil/mem/mem_freebsd.go +++ b/vendor/github.com/shirou/gopsutil/mem/mem_freebsd.go @@ -39,7 +39,7 @@ func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { if err != nil { return nil, err } - buffers, err := unix.SysctlUint32("vfs.bufspace") + buffers, err := unix.SysctlUint64("vfs.bufspace") if err != nil { return nil, err } From 3387d4c79293bdfc90bd05e6b65513b4637c4ef0 Mon Sep 17 00:00:00 2001 From: Caleb Bassi Date: Tue, 15 May 2018 13:46:50 -0700 Subject: [PATCH 2/4] Add back files removed from gopsutil --- src/widgets/include/smc.c | 700 ++++++++++++++++++++++++++++++++++++++ src/widgets/include/smc.h | 254 ++++++++++++++ 2 files changed, 954 insertions(+) create mode 100644 src/widgets/include/smc.c create mode 100644 src/widgets/include/smc.h diff --git a/src/widgets/include/smc.c b/src/widgets/include/smc.c new file mode 100644 index 0000000..82b4a0a --- /dev/null +++ b/src/widgets/include/smc.c @@ -0,0 +1,700 @@ +/* + * Apple System Management Controller (SMC) API from user space for Intel based + * Macs. Works by talking to the AppleSMC.kext (kernel extension), the driver + * for the SMC. + * + * smc.c + * libsmc + * + * Copyright (C) 2014 beltex + * + * Based off of fork from: + * osx-cpu-temp + * + * With credits to: + * + * Copyright (C) 2006 devnull + * Apple System Management Control (SMC) Tool + * + * Copyright (C) 2006 Hendrik Holtmann + * smcFanControl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include "smc.h" + + +//------------------------------------------------------------------------------ +// MARK: MACROS +//------------------------------------------------------------------------------ + + +/** +Name of the SMC IOService as seen in the IORegistry. You can view it either via +command line with ioreg or through the IORegistryExplorer app (found on Apple's +developer site - Hardware IO Tools for Xcode) +*/ +#define IOSERVICE_SMC "AppleSMC" + + +/** +IOService for getting machine model name +*/ +#define IOSERVICE_MODEL "IOPlatformExpertDevice" + + +/** +SMC data types - 4 byte multi-character constants + +Sources: See TMP SMC keys in smc.h + +http://stackoverflow.com/questions/22160746/fpe2-and-sp78-data-types +*/ +#define DATA_TYPE_UINT8 "ui8 " +#define DATA_TYPE_UINT16 "ui16" +#define DATA_TYPE_UINT32 "ui32" +#define DATA_TYPE_FLAG "flag" +#define DATA_TYPE_FPE2 "fpe2" +#define DATA_TYPE_SFDS "{fds" +#define DATA_TYPE_SP78 "sp78" + + +//------------------------------------------------------------------------------ +// MARK: GLOBAL VARS +//------------------------------------------------------------------------------ + + +/** +Our connection to the SMC +*/ +static io_connect_t conn; + + +/** +Number of characters in an SMC key +*/ +static const int SMC_KEY_SIZE = 4; + + +/** +Number of characters in a data type "key" returned from the SMC. See data type +macros. +*/ +static const int DATA_TYPE_SIZE = 4; + + +//------------------------------------------------------------------------------ +// MARK: ENUMS +//------------------------------------------------------------------------------ + + +/** +Defined by AppleSMC.kext. See SMCParamStruct. + +These are SMC specific return codes +*/ +typedef enum { + kSMCSuccess = 0, + kSMCError = 1, + kSMCKeyNotFound = 0x84 +} kSMC_t; + + +/** +Defined by AppleSMC.kext. See SMCParamStruct. + +Function selectors. Used to tell the SMC which function inside it to call. +*/ +typedef enum { + kSMCUserClientOpen = 0, + kSMCUserClientClose = 1, + kSMCHandleYPCEvent = 2, + kSMCReadKey = 5, + kSMCWriteKey = 6, + kSMCGetKeyCount = 7, + kSMCGetKeyFromIndex = 8, + kSMCGetKeyInfo = 9 +} selector_t; + + +//------------------------------------------------------------------------------ +// MARK: STRUCTS +//------------------------------------------------------------------------------ + + +/** +Defined by AppleSMC.kext. See SMCParamStruct. +*/ +typedef struct { + unsigned char major; + unsigned char minor; + unsigned char build; + unsigned char reserved; + unsigned short release; +} SMCVersion; + + +/** +Defined by AppleSMC.kext. See SMCParamStruct. +*/ +typedef struct { + uint16_t version; + uint16_t length; + uint32_t cpuPLimit; + uint32_t gpuPLimit; + uint32_t memPLimit; +} SMCPLimitData; + + +/** +Defined by AppleSMC.kext. See SMCParamStruct. + +- dataSize : How many values written to SMCParamStruct.bytes +- dataType : Type of data written to SMCParamStruct.bytes. This lets us know how + to interpret it (translate it to human readable) +*/ +typedef struct { + IOByteCount dataSize; + uint32_t dataType; + uint8_t dataAttributes; +} SMCKeyInfoData; + + +/** +Defined by AppleSMC.kext. + +This is the predefined struct that must be passed to communicate with the +AppleSMC driver. While the driver is closed source, the definition of this +struct happened to appear in the Apple PowerManagement project at around +version 211, and soon after disappeared. It can be seen in the PrivateLib.c +file under pmconfigd. + +https://www.opensource.apple.com/source/PowerManagement/PowerManagement-211/ +*/ +typedef struct { + uint32_t key; + SMCVersion vers; + SMCPLimitData pLimitData; + SMCKeyInfoData keyInfo; + uint8_t result; + uint8_t status; + uint8_t data8; + uint32_t data32; + uint8_t bytes[32]; +} SMCParamStruct; + + +/** +Used for returning data from the SMC. +*/ +typedef struct { + uint8_t data[32]; + uint32_t dataType; + uint32_t dataSize; + kSMC_t kSMC; +} smc_return_t; + + +//------------------------------------------------------------------------------ +// MARK: HELPERS - TYPE CONVERSION +//------------------------------------------------------------------------------ + + +/** +Convert data from SMC of fpe2 type to human readable. + +:param: data Data from the SMC to be converted. Assumed data size of 2. +:returns: Converted data +*/ +static unsigned int from_fpe2(uint8_t data[32]) +{ + unsigned int ans = 0; + + // Data type for fan calls - fpe2 + // This is assumend to mean floating point, with 2 exponent bits + // http://stackoverflow.com/questions/22160746/fpe2-and-sp78-data-types + ans += data[0] << 6; + ans += data[1] << 2; + + return ans; +} + + +/** +Convert to fpe2 data type to be passed to SMC. + +:param: val Value to convert +:param: data Pointer to data array to place result +*/ +static void to_fpe2(unsigned int val, uint8_t *data) +{ + data[0] = val >> 6; + data[1] = (val << 2) ^ (data[0] << 8); +} + + +/** +Convert SMC key to uint32_t. This must be done to pass it to the SMC. + +:param: key The SMC key to convert +:returns: uint32_t translation. + Returns zero if key is not 4 characters in length. +*/ +static uint32_t to_uint32_t(char *key) +{ + uint32_t ans = 0; + uint32_t shift = 24; + + // SMC key is expected to be 4 bytes - thus 4 chars + 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; +} + + +/** +For converting the dataType return from the SMC to human readable 4 byte +multi-character constant. +*/ +static void to_string(uint32_t val, char *dataType) +{ + int shift = 24; + + for (int i = 0; i < DATA_TYPE_SIZE; i++) { + // To get each char, we shift it into the lower 8 bits, and then & by + // 255 to insolate it + dataType[i] = (val >> shift) & 0xff; + shift -= 8; + } +} + + +//------------------------------------------------------------------------------ +// MARK: HELPERS - TMP CONVERSION +//------------------------------------------------------------------------------ + + +/** +Celsius to Fahrenheit +*/ +static double to_fahrenheit(double tmp) +{ + // http://en.wikipedia.org/wiki/Fahrenheit#Definition_and_conversions + return (tmp * 1.8) + 32; +} + + +/** +Celsius to Kelvin +*/ +static double to_kelvin(double tmp) +{ + // http://en.wikipedia.org/wiki/Kelvin + return tmp + 273.15; +} + + +//------------------------------------------------------------------------------ +// MARK: "PRIVATE" FUNCTIONS +//------------------------------------------------------------------------------ + + +/** +Make a call to the SMC + +:param: inputStruct Struct that holds data telling the SMC what you want +:param: outputStruct Struct holding the SMC's response +:returns: I/O Kit return code +*/ +static kern_return_t call_smc(SMCParamStruct *inputStruct, + SMCParamStruct *outputStruct) +{ + kern_return_t result; + size_t inputStructCnt = sizeof(SMCParamStruct); + size_t outputStructCnt = sizeof(SMCParamStruct); + + result = IOConnectCallStructMethod(conn, kSMCHandleYPCEvent, + inputStruct, + inputStructCnt, + outputStruct, + &outputStructCnt); + + if (result != kIOReturnSuccess) { + // IOReturn error code lookup. See "Accessing Hardware From Applications + // -> Handling Errors" Apple doc + result = err_get_code(result); + } + + return result; +} + + +/** +Read data from the SMC + +:param: key The SMC key +*/ +static kern_return_t read_smc(char *key, smc_return_t *result_smc) +{ + kern_return_t result; + SMCParamStruct inputStruct; + SMCParamStruct outputStruct; + + memset(&inputStruct, 0, sizeof(SMCParamStruct)); + memset(&outputStruct, 0, sizeof(SMCParamStruct)); + memset(result_smc, 0, sizeof(smc_return_t)); + + // First call to AppleSMC - get key info + inputStruct.key = to_uint32_t(key); + inputStruct.data8 = kSMCGetKeyInfo; + + result = call_smc(&inputStruct, &outputStruct); + result_smc->kSMC = outputStruct.result; + + if (result != kIOReturnSuccess || outputStruct.result != kSMCSuccess) { + return result; + } + + // Store data for return + result_smc->dataSize = outputStruct.keyInfo.dataSize; + result_smc->dataType = outputStruct.keyInfo.dataType; + + + // Second call to AppleSMC - now we can get the data + inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize; + inputStruct.data8 = kSMCReadKey; + + result = call_smc(&inputStruct, &outputStruct); + result_smc->kSMC = outputStruct.result; + + if (result != kIOReturnSuccess || outputStruct.result != kSMCSuccess) { + return result; + } + + memcpy(result_smc->data, outputStruct.bytes, sizeof(outputStruct.bytes)); + + return result; +} + + +/** +Write data to the SMC. + +:returns: IOReturn IOKit return code +*/ +static kern_return_t write_smc(char *key, smc_return_t *result_smc) +{ + kern_return_t result; + SMCParamStruct inputStruct; + SMCParamStruct outputStruct; + + memset(&inputStruct, 0, sizeof(SMCParamStruct)); + memset(&outputStruct, 0, sizeof(SMCParamStruct)); + + // First call to AppleSMC - get key info + inputStruct.key = to_uint32_t(key); + inputStruct.data8 = kSMCGetKeyInfo; + + result = call_smc(&inputStruct, &outputStruct); + result_smc->kSMC = outputStruct.result; + + if (result != kIOReturnSuccess || outputStruct.result != kSMCSuccess) { + return result; + } + + // Check data is correct + if (result_smc->dataSize != outputStruct.keyInfo.dataSize || + result_smc->dataType != outputStruct.keyInfo.dataType) { + return kIOReturnBadArgument; + } + + // Second call to AppleSMC - now we can write the data + inputStruct.data8 = kSMCWriteKey; + inputStruct.keyInfo.dataSize = outputStruct.keyInfo.dataSize; + + // Set data to write + memcpy(inputStruct.bytes, result_smc->data, sizeof(result_smc->data)); + + result = call_smc(&inputStruct, &outputStruct); + result_smc->kSMC = outputStruct.result; + + return result; +} + + +/** +Get the model name of the machine. +*/ +static kern_return_t get_machine_model(io_name_t model) +{ + io_service_t service; + kern_return_t result; + + service = IOServiceGetMatchingService(kIOMasterPortDefault, + IOServiceMatching(IOSERVICE_MODEL)); + + if (service == 0) { + printf("ERROR: %s NOT FOUND\n", IOSERVICE_MODEL); + return kIOReturnError; + } + + // Get the model name + result = IORegistryEntryGetName(service, model); + IOObjectRelease(service); + + return result; +} + + +//------------------------------------------------------------------------------ +// MARK: "PUBLIC" FUNCTIONS +//------------------------------------------------------------------------------ + + +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); +} + + +bool is_key_valid(char *key) +{ + bool ans = false; + kern_return_t result; + smc_return_t result_smc; + + if (strlen(key) != SMC_KEY_SIZE) { + printf("ERROR: Invalid key size - must be 4 chars\n"); + return ans; + } + + // Try a read and see if it succeeds + result = read_smc(key, &result_smc); + + if (result == kIOReturnSuccess && result_smc.kSMC == kSMCSuccess) { + ans = true; + } + + return ans; +} + + +double get_tmp(char *key, tmp_unit_t unit) +{ + kern_return_t result; + smc_return_t result_smc; + + result = read_smc(key, &result_smc); + + if (!(result == kIOReturnSuccess && + result_smc.dataSize == 2 && + result_smc.dataType == to_uint32_t(DATA_TYPE_SP78))) { + // Error + return 0.0; + } + + // TODO: Create from_sp78() convert function + double tmp = result_smc.data[0]; + + switch (unit) { + case CELSIUS: + break; + case FAHRENHEIT: + tmp = to_fahrenheit(tmp); + break; + case KELVIN: + tmp = to_kelvin(tmp); + break; + } + + return tmp; +} + + +bool is_battery_powered(void) +{ + kern_return_t result; + smc_return_t result_smc; + + result = read_smc(BATT_PWR, &result_smc); + + if (!(result == kIOReturnSuccess && + result_smc.dataSize == 1 && + result_smc.dataType == to_uint32_t(DATA_TYPE_FLAG))) { + // Error + return false; + } + + return result_smc.data[0]; +} + + +bool is_optical_disk_drive_full(void) +{ + kern_return_t result; + smc_return_t result_smc; + + result = read_smc(ODD_FULL, &result_smc); + + if (!(result == kIOReturnSuccess && + result_smc.dataSize == 1 && + result_smc.dataType == to_uint32_t(DATA_TYPE_FLAG))) { + // Error + return false; + } + + return result_smc.data[0]; +} + + +//------------------------------------------------------------------------------ +// MARK: FAN FUNCTIONS +//------------------------------------------------------------------------------ + + +bool get_fan_name(unsigned int fan_num, fan_name_t name) +{ + char key[5]; + kern_return_t result; + smc_return_t result_smc; + + sprintf(key, "F%dID", fan_num); + result = read_smc(key, &result_smc); + + if (!(result == kIOReturnSuccess && + result_smc.dataSize == 16 && + result_smc.dataType == to_uint32_t(DATA_TYPE_SFDS))) { + return false; + } + + + /* + We know the data size is 16 bytes and the type is "{fds", a custom + struct defined by the AppleSMC.kext. See TMP enum sources for the + struct. + + The last 12 bytes contain the name of the fan, an array of chars, hence + the loop range. + */ + int index = 0; + for (int i = 4; i < 16; i++) { + // Check if at the end (name may not be full 12 bytes) + // Could check for 0 (null), but instead we check for 32 (space). This + // is a hack to remove whitespace. :) + if (result_smc.data[i] == 32) { + break; + } + + name[index] = result_smc.data[i]; + index++; + } + + return true; +} + + +int get_num_fans(void) +{ + kern_return_t result; + smc_return_t result_smc; + + result = read_smc(NUM_FANS, &result_smc); + + if (!(result == kIOReturnSuccess && + result_smc.dataSize == 1 && + result_smc.dataType == to_uint32_t(DATA_TYPE_UINT8))) { + // Error + return -1; + } + + return result_smc.data[0]; +} + + +unsigned int get_fan_rpm(unsigned int fan_num) +{ + char key[5]; + kern_return_t result; + smc_return_t result_smc; + + sprintf(key, "F%dAc", fan_num); + result = read_smc(key, &result_smc); + + if (!(result == kIOReturnSuccess && + result_smc.dataSize == 2 && + result_smc.dataType == to_uint32_t(DATA_TYPE_FPE2))) { + // Error + return 0; + } + + return from_fpe2(result_smc.data); +} + + +bool set_fan_min_rpm(unsigned int fan_num, unsigned int rpm, bool auth) +{ + // TODO: Add rpm val safety check + char key[5]; + bool ans = false; + kern_return_t result; + smc_return_t result_smc; + + memset(&result_smc, 0, sizeof(smc_return_t)); + + // TODO: Don't use magic number + result_smc.dataSize = 2; + result_smc.dataType = to_uint32_t(DATA_TYPE_FPE2); + to_fpe2(rpm, result_smc.data); + + sprintf(key, "F%dMn", fan_num); + result = write_smc(key, &result_smc); + + if (result == kIOReturnSuccess && result_smc.kSMC == kSMCSuccess) { + ans = true; + } + + return ans; +} diff --git a/src/widgets/include/smc.h b/src/widgets/include/smc.h new file mode 100644 index 0000000..d837e11 --- /dev/null +++ b/src/widgets/include/smc.h @@ -0,0 +1,254 @@ +/* + * Apple System Management Controller (SMC) API from user space for Intel based + * Macs. Works by talking to the AppleSMC.kext (kernel extension), the driver + * for the SMC. + * + * smc.h + * libsmc + * + * Copyright (C) 2014 beltex + * + * Based off of fork from: + * osx-cpu-temp + * + * With credits to: + * + * Copyright (C) 2006 devnull + * Apple System Management Control (SMC) Tool + * + * Copyright (C) 2006 Hendrik Holtmann + * smcFanControl + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + + +//------------------------------------------------------------------------------ +// MARK: MACROS +//------------------------------------------------------------------------------ + + +/** +SMC keys for temperature sensors - 4 byte multi-character constants + +Not applicable to all Mac's of course. In adition, the definition of the codes +may not be 100% accurate necessarily. Finally, list is incomplete. + +Presumed letter translations: + +- T = Temperature (if first char) +- C = CPU +- G = GPU +- P = Proximity +- D = Diode +- H = Heatsink + +Sources: + +- https://www.apple.com/downloads/dashboard/status/istatpro.html +- https://github.com/hholtmann/smcFanControl +- https://github.com/jedda/OSX-Monitoring-Tools +- http://www.parhelia.ch/blog/statics/k3_keys.html +*/ +#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" + + +/** +SMC keys for fans - 4 byte multi-character constants + +Number of fans on Macs vary of course, thus not all keys will be applicable. + +Presumed letter translations: + +- F = Fan +- Ac = Acutal +- Mn = Min +- Mx = Max +- Sf = Safe +- Tg = Target + +Sources: See TMP SMC keys +*/ +#define FAN_0 "F0Ac" +#define FAN_0_MIN_RPM "F0Mn" +#define FAN_0_MAX_RPM "F0Mx" +#define FAN_0_SAFE_RPM "F0Sf" +#define FAN_0_TARGET_RPM "F0Tg" +#define FAN_1 "F1Ac" +#define FAN_1_MIN_RPM "F1Mn" +#define FAN_1_MAX_RPM "F1Mx" +#define FAN_1_SAFE_RPM "F1Sf" +#define FAN_1_TARGET_RPM "F1Tg" +#define FAN_2 "F2Ac" +#define FAN_2_MIN_RPM "F2Mn" +#define FAN_2_MAX_RPM "F2Mx" +#define FAN_2_SAFE_RPM "F2Sf" +#define FAN_2_TARGET_RPM "F2Tg" +#define NUM_FANS "FNum" +#define FORCE_BITS "FS! " + + +/** +Misc SMC keys - 4 byte multi-character constants + +Sources: See TMP SMC keys +*/ +#define BATT_PWR "BATP" +#define NUM_KEYS "#KEY" +#define ODD_FULL "MSDI" + + +//------------------------------------------------------------------------------ +// MARK: TYPES +//------------------------------------------------------------------------------ + + +typedef char fan_name_t[13]; + + +//------------------------------------------------------------------------------ +// MARK: ENUMS +//------------------------------------------------------------------------------ + + +typedef enum { + CELSIUS, + FAHRENHEIT, + KELVIN +} tmp_unit_t; + + +//------------------------------------------------------------------------------ +// MARK: PROTOTYPES +//------------------------------------------------------------------------------ + + +/** +Open a connection to the SMC + +:returns: kIOReturnSuccess on successful connection to the SMC. +*/ +kern_return_t open_smc(void); + + +/** +Close connection to the SMC + +:returns: kIOReturnSuccess on successful close of connection to the SMC. +*/ +kern_return_t close_smc(void); + + +/** +Check if an SMC key is valid. Useful for determining if a certain machine has +particular sensor or fan for example. + +:param: key The SMC key to check. 4 byte multi-character constant. Must be 4 + characters in length. +:returns: True if the key is found, false otherwise +*/ +bool is_key_valid(char *key); + + +/** +Get the current temperature from a sensor + +:param: key The temperature sensor to read from +:param: unit The unit for the temperature value. +:returns: Temperature of sensor. If the sensor is not found, or an error + occurs, return will be zero +*/ +double get_tmp(char *key, tmp_unit_t unit); + + +/** +Is the machine being powered by the battery? + +:returns: True if it is, false otherwise +*/ +bool is_battery_powered(void); + + +/** +Is there a CD in the optical disk drive (ODD)? + +:returns: True if there is, false otherwise +*/ +bool is_optical_disk_drive_full(void); + + +/** +Get the name of a fan. + +:param: fanNum The number of the fan to check +:param: name The name of the fan. Return will be empty on error. +:returns: True if successful, false otherwise. +*/ +bool get_fan_name(unsigned int fan_num, fan_name_t name); + + +/** +Get the number of fans on this machine. + +:returns: The number of fans. If an error occurs, return will be -1. +*/ +int get_num_fans(void); + + +/** +Get the current speed (RPM - revolutions per minute) of a fan. + +:param: fan_num The number of the fan to check +:returns: The fan RPM. If the fan is not found, or an error occurs, return + will be zero +*/ +UInt get_fan_rpm(UInt fan_num); + + +/** +Set the minimum speed (RPM - revolutions per minute) of a fan. This method +requires root privileges. By minimum we mean that OS X can interject and +raise the fan speed if needed, however it will not go below this. + +WARNING: You are playing with hardware here, BE CAREFUL. + +:param: fan_num The number of the fan to set +:param: rpm The speed you would like to set the fan to. +:param: auth Should the function do authentication? +:return: True if successful, false otherwise +*/ +bool set_fan_min_rpm(unsigned int fan_num, unsigned int rpm, bool auth); From 6f4984e5e7f75c1a236de2c98a9a0482697913e8 Mon Sep 17 00:00:00 2001 From: Caleb Bassi Date: Tue, 15 May 2018 13:48:26 -0700 Subject: [PATCH 3/4] Separate temp widget by platform --- src/widgets/temp.go | 15 ---------- src/widgets/temp_darwin.go | 57 +++++++++++++++++++++++++++++++++++++ src/widgets/temp_linux.go | 19 +++++++++++++ src/widgets/temp_windows.go | 12 ++++++++ 4 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 src/widgets/temp_darwin.go create mode 100644 src/widgets/temp_linux.go create mode 100644 src/widgets/temp_windows.go diff --git a/src/widgets/temp.go b/src/widgets/temp.go index 2759c1a..c366cb2 100644 --- a/src/widgets/temp.go +++ b/src/widgets/temp.go @@ -6,11 +6,9 @@ package widgets import ( "fmt" "sort" - "strings" "time" ui "github.com/cjbassi/termui" - psHost "github.com/shirou/gopsutil/host" ) type Temp struct { @@ -43,18 +41,6 @@ func NewTemp() *Temp { return self } -func (self *Temp) update() { - sensors, _ := psHost.SensorsTemperatures() - for _, sensor := range sensors { - // only sensors with input in their name are giving us live temp info - if strings.Contains(sensor.SensorKey, "input") { - // removes '_input' from the end of the sensor name - label := sensor.SensorKey[:strings.Index(sensor.SensorKey, "_input")] - self.Data[label] = int(sensor.Temperature) - } - } -} - // Buffer implements ui.Bufferer interface and renders the widget. func (self *Temp) Buffer() *ui.Buffer { buf := self.Block.Buffer() @@ -78,7 +64,6 @@ func (self *Temp) Buffer() *ui.Buffer { s := ui.MaxString(key, (self.X - 4)) buf.SetString(1, y+1, s, self.Fg, self.Bg) buf.SetString(self.X-2, y+1, fmt.Sprintf("%2dC", self.Data[key]), fg, self.Bg) - } return buf diff --git a/src/widgets/temp_darwin.go b/src/widgets/temp_darwin.go new file mode 100644 index 0000000..910cfed --- /dev/null +++ b/src/widgets/temp_darwin.go @@ -0,0 +1,57 @@ +// TODO do we need to add '+build cgo'? + +package widgets + +// #cgo LDFLAGS: -framework IOKit +// #include "include/smc.c" +import "C" + +type TemperatureStat struct { + SensorKey string `json:"sensorKey"` + Temperature float64 `json:"sensorTemperature"` +} + +func SensorsTempatures() ([]TemperatureStat, error) { + temperatureKeys := []string{ + C.AMBIENT_AIR_0, + C.AMBIENT_AIR_1, + C.CPU_0_DIODE, + C.CPU_0_HEATSINK, + C.CPU_0_PROXIMITY, + C.ENCLOSURE_BASE_0, + C.ENCLOSURE_BASE_1, + C.ENCLOSURE_BASE_2, + C.ENCLOSURE_BASE_3, + C.GPU_0_DIODE, + C.GPU_0_HEATSINK, + C.GPU_0_PROXIMITY, + C.HARD_DRIVE_BAY, + C.MEMORY_SLOT_0, + C.MEMORY_SLOTS_PROXIMITY, + C.NORTHBRIDGE, + C.NORTHBRIDGE_DIODE, + C.NORTHBRIDGE_PROXIMITY, + C.THUNDERBOLT_0, + C.THUNDERBOLT_1, + C.WIRELESS_MODULE, + } + var temperatures []TemperatureStat + + C.open_smc() + defer C.close_smc() + + for _, key := range temperatureKeys { + temperatures = append(temperatures, TemperatureStat{ + SensorKey: key, + Temperature: float64(C.get_tmp(C.CString(key), C.CELSIUS)), + }) + } + return temperatures, nil +} + +func (self *Temp) update() { + sensors, _ := SensorsTemperatures() + for _, sensor := range sensors { + self.Data[sensor.SensorKey] = int(sensor.Temperature) + } +} diff --git a/src/widgets/temp_linux.go b/src/widgets/temp_linux.go new file mode 100644 index 0000000..e818863 --- /dev/null +++ b/src/widgets/temp_linux.go @@ -0,0 +1,19 @@ +package widgets + +import ( + "strings" + + psHost "github.com/shirou/gopsutil/host" +) + +func (self *Temp) update() { + sensors, _ := psHost.SensorsTemperatures() + for _, sensor := range sensors { + // only sensors with input in their name are giving us live temp info + if strings.Contains(sensor.SensorKey, "input") { + // removes '_input' from the end of the sensor name + label := sensor.SensorKey[:strings.Index(sensor.SensorKey, "_input")] + self.Data[label] = int(sensor.Temperature) + } + } +} diff --git a/src/widgets/temp_windows.go b/src/widgets/temp_windows.go new file mode 100644 index 0000000..99c2a87 --- /dev/null +++ b/src/widgets/temp_windows.go @@ -0,0 +1,12 @@ +package widgets + +import ( + psHost "github.com/shirou/gopsutil/host" +) + +func (self *Temp) update() { + sensors, _ := psHost.SensorsTemperatures() + for _, sensor := range sensors { + self.Data[sensor.SensorKey] = int(sensor.Temperature) + } +} From 08ea0b3db0c220d7f23c93c24c5fbfa36e2e7208 Mon Sep 17 00:00:00 2001 From: Michael R Fleet Date: Wed, 23 May 2018 22:09:04 -0400 Subject: [PATCH 4/4] fix typo in temp_darwin --- src/widgets/temp_darwin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/temp_darwin.go b/src/widgets/temp_darwin.go index 910cfed..d635dd7 100644 --- a/src/widgets/temp_darwin.go +++ b/src/widgets/temp_darwin.go @@ -11,7 +11,7 @@ type TemperatureStat struct { Temperature float64 `json:"sensorTemperature"` } -func SensorsTempatures() ([]TemperatureStat, error) { +func SensorsTemperatures() ([]TemperatureStat, error) { temperatureKeys := []string{ C.AMBIENT_AIR_0, C.AMBIENT_AIR_1,