diff --git a/vendor/github.com/StackExchange/wmi/README.md b/vendor/github.com/StackExchange/wmi/README.md index 3d5f67e149b..426d1a46b4a 100644 --- a/vendor/github.com/StackExchange/wmi/README.md +++ b/vendor/github.com/StackExchange/wmi/README.md @@ -1,4 +1,6 @@ wmi === -Package wmi provides a WQL interface for WMI on Windows. +Package wmi provides a WQL interface to Windows WMI. + +Note: It interfaces with WMI on the local machine, therefore it only runs on Windows. diff --git a/vendor/github.com/StackExchange/wmi/swbemservices.go b/vendor/github.com/StackExchange/wmi/swbemservices.go new file mode 100644 index 00000000000..9765a53f74d --- /dev/null +++ b/vendor/github.com/StackExchange/wmi/swbemservices.go @@ -0,0 +1,260 @@ +// +build windows + +package wmi + +import ( + "fmt" + "reflect" + "runtime" + "sync" + + "github.com/go-ole/go-ole" + "github.com/go-ole/go-ole/oleutil" +) + +// SWbemServices is used to access wmi. See https://msdn.microsoft.com/en-us/library/aa393719(v=vs.85).aspx +type SWbemServices struct { + //TODO: track namespace. Not sure if we can re connect to a different namespace using the same instance + cWMIClient *Client //This could also be an embedded struct, but then we would need to branch on Client vs SWbemServices in the Query method + sWbemLocatorIUnknown *ole.IUnknown + sWbemLocatorIDispatch *ole.IDispatch + queries chan *queryRequest + closeError chan error + lQueryorClose sync.Mutex +} + +type queryRequest struct { + query string + dst interface{} + args []interface{} + finished chan error +} + +// InitializeSWbemServices will return a new SWbemServices object that can be used to query WMI +func InitializeSWbemServices(c *Client, connectServerArgs ...interface{}) (*SWbemServices, error) { + //fmt.Println("InitializeSWbemServices: Starting") + //TODO: implement connectServerArgs as optional argument for init with connectServer call + s := new(SWbemServices) + s.cWMIClient = c + s.queries = make(chan *queryRequest) + initError := make(chan error) + go s.process(initError) + + err, ok := <-initError + if ok { + return nil, err //Send error to caller + } + //fmt.Println("InitializeSWbemServices: Finished") + return s, nil +} + +// Close will clear and release all of the SWbemServices resources +func (s *SWbemServices) Close() error { + s.lQueryorClose.Lock() + if s == nil || s.sWbemLocatorIDispatch == nil { + s.lQueryorClose.Unlock() + return fmt.Errorf("SWbemServices is not Initialized") + } + if s.queries == nil { + s.lQueryorClose.Unlock() + return fmt.Errorf("SWbemServices has been closed") + } + //fmt.Println("Close: sending close request") + var result error + ce := make(chan error) + s.closeError = ce //Race condition if multiple callers to close. May need to lock here + close(s.queries) //Tell background to shut things down + s.lQueryorClose.Unlock() + err, ok := <-ce + if ok { + result = err + } + //fmt.Println("Close: finished") + return result +} + +func (s *SWbemServices) process(initError chan error) { + //fmt.Println("process: starting background thread initialization") + //All OLE/WMI calls must happen on the same initialized thead, so lock this goroutine + runtime.LockOSThread() + defer runtime.LockOSThread() + + err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED) + if err != nil { + oleCode := err.(*ole.OleError).Code() + if oleCode != ole.S_OK && oleCode != S_FALSE { + initError <- fmt.Errorf("ole.CoInitializeEx error: %v", err) + return + } + } + defer ole.CoUninitialize() + + unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator") + if err != nil { + initError <- fmt.Errorf("CreateObject SWbemLocator error: %v", err) + return + } else if unknown == nil { + initError <- ErrNilCreateObject + return + } + defer unknown.Release() + s.sWbemLocatorIUnknown = unknown + + dispatch, err := s.sWbemLocatorIUnknown.QueryInterface(ole.IID_IDispatch) + if err != nil { + initError <- fmt.Errorf("SWbemLocator QueryInterface error: %v", err) + return + } + defer dispatch.Release() + s.sWbemLocatorIDispatch = dispatch + + // we can't do the ConnectServer call outside the loop unless we find a way to track and re-init the connectServerArgs + //fmt.Println("process: initialized. closing initError") + close(initError) + //fmt.Println("process: waiting for queries") + for q := range s.queries { + //fmt.Printf("process: new query: len(query)=%d\n", len(q.query)) + errQuery := s.queryBackground(q) + //fmt.Println("process: s.queryBackground finished") + if errQuery != nil { + q.finished <- errQuery + } + close(q.finished) + } + //fmt.Println("process: queries channel closed") + s.queries = nil //set channel to nil so we know it is closed + //TODO: I think the Release/Clear calls can panic if things are in a bad state. + //TODO: May need to recover from panics and send error to method caller instead. + close(s.closeError) +} + +// Query runs the WQL query using a SWbemServices instance and appends the values to dst. +// +// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in +// the query must have the same name in dst. Supported types are all signed and +// unsigned integers, time.Time, string, bool, or a pointer to one of those. +// Array types are not supported. +// +// By default, the local machine and default namespace are used. These can be +// changed using connectServerArgs. See +// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details. +func (s *SWbemServices) Query(query string, dst interface{}, connectServerArgs ...interface{}) error { + s.lQueryorClose.Lock() + if s == nil || s.sWbemLocatorIDispatch == nil { + s.lQueryorClose.Unlock() + return fmt.Errorf("SWbemServices is not Initialized") + } + if s.queries == nil { + s.lQueryorClose.Unlock() + return fmt.Errorf("SWbemServices has been closed") + } + + //fmt.Println("Query: Sending query request") + qr := queryRequest{ + query: query, + dst: dst, + args: connectServerArgs, + finished: make(chan error), + } + s.queries <- &qr + s.lQueryorClose.Unlock() + err, ok := <-qr.finished + if ok { + //fmt.Println("Query: Finished with error") + return err //Send error to caller + } + //fmt.Println("Query: Finished") + return nil +} + +func (s *SWbemServices) queryBackground(q *queryRequest) error { + if s == nil || s.sWbemLocatorIDispatch == nil { + return fmt.Errorf("SWbemServices is not Initialized") + } + wmi := s.sWbemLocatorIDispatch //Should just rename in the code, but this will help as we break things apart + //fmt.Println("queryBackground: Starting") + + dv := reflect.ValueOf(q.dst) + if dv.Kind() != reflect.Ptr || dv.IsNil() { + return ErrInvalidEntityType + } + dv = dv.Elem() + mat, elemType := checkMultiArg(dv) + if mat == multiArgTypeInvalid { + return ErrInvalidEntityType + } + + // service is a SWbemServices + serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", q.args...) + if err != nil { + return err + } + service := serviceRaw.ToIDispatch() + defer serviceRaw.Clear() + + // result is a SWBemObjectSet + resultRaw, err := oleutil.CallMethod(service, "ExecQuery", q.query) + if err != nil { + return err + } + result := resultRaw.ToIDispatch() + defer resultRaw.Clear() + + count, err := oleInt64(result, "Count") + if err != nil { + return err + } + + enumProperty, err := result.GetProperty("_NewEnum") + if err != nil { + return err + } + defer enumProperty.Clear() + + enum, err := enumProperty.ToIUnknown().IEnumVARIANT(ole.IID_IEnumVariant) + if err != nil { + return err + } + if enum == nil { + return fmt.Errorf("can't get IEnumVARIANT, enum is nil") + } + defer enum.Release() + + // Initialize a slice with Count capacity + dv.Set(reflect.MakeSlice(dv.Type(), 0, int(count))) + + var errFieldMismatch error + for itemRaw, length, err := enum.Next(1); length > 0; itemRaw, length, err = enum.Next(1) { + if err != nil { + return err + } + + err := func() error { + // item is a SWbemObject, but really a Win32_Process + item := itemRaw.ToIDispatch() + defer item.Release() + + ev := reflect.New(elemType) + if err = s.cWMIClient.loadEntity(ev.Interface(), item); err != nil { + if _, ok := err.(*ErrFieldMismatch); ok { + // We continue loading entities even in the face of field mismatch errors. + // If we encounter any other error, that other error is returned. Otherwise, + // an ErrFieldMismatch is returned. + errFieldMismatch = err + } else { + return err + } + } + if mat != multiArgTypeStructPtr { + ev = ev.Elem() + } + dv.Set(reflect.Append(dv, ev)) + return nil + }() + if err != nil { + return err + } + } + //fmt.Println("queryBackground: Finished") + return errFieldMismatch +} diff --git a/vendor/github.com/StackExchange/wmi/wmi.go b/vendor/github.com/StackExchange/wmi/wmi.go index 5cb56ff1ec9..9c688b03841 100644 --- a/vendor/github.com/StackExchange/wmi/wmi.go +++ b/vendor/github.com/StackExchange/wmi/wmi.go @@ -72,7 +72,10 @@ func QueryNamespace(query string, dst interface{}, namespace string) error { // // Query is a wrapper around DefaultClient.Query. func Query(query string, dst interface{}, connectServerArgs ...interface{}) error { - return DefaultClient.Query(query, dst, connectServerArgs...) + if DefaultClient.SWbemServicesClient == nil { + return DefaultClient.Query(query, dst, connectServerArgs...) + } + return DefaultClient.SWbemServicesClient.Query(query, dst, connectServerArgs...) } // A Client is an WMI query client. @@ -99,6 +102,11 @@ type Client struct { // Setting this to true allows custom queries to be used with full // struct definitions instead of having to define multiple structs. AllowMissingFields bool + + // SWbemServiceClient is an optional SWbemServices object that can be + // initialized and then reused across multiple queries. If it is null + // then the method will initialize a new temporary client each time. + SWbemServicesClient *SWbemServices } // DefaultClient is the default Client and is used by Query, QueryNamespace @@ -362,6 +370,21 @@ func (c *Client) loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismat } } default: + // Only support []string slices for now + if f.Kind() == reflect.Slice && f.Type().Elem().Kind() == reflect.String { + safeArray := prop.ToArray() + if safeArray != nil { + arr := safeArray.ToValueArray() + fArr := reflect.MakeSlice(f.Type(), len(arr), len(arr)) + for i, v := range arr { + s := fArr.Index(i) + s.SetString(v.(string)) + } + f.Set(fArr) + break + } + } + typeof := reflect.TypeOf(val) if typeof == nil && (isPtr || c.NonePtrZero) { if (isPtr && c.PtrNil) || (!isPtr && c.NonePtrZero) { diff --git a/vendor/github.com/go-ole/go-ole/ChangeLog.md b/vendor/github.com/go-ole/go-ole/ChangeLog.md new file mode 100644 index 00000000000..4ba6a8c64d0 --- /dev/null +++ b/vendor/github.com/go-ole/go-ole/ChangeLog.md @@ -0,0 +1,49 @@ +# Version 1.x.x + +* **Add more test cases and reference new test COM server project.** (Placeholder for future additions) + +# Version 1.2.0-alphaX + +**Minimum supported version is now Go 1.4. Go 1.1 support is deprecated, but should still build.** + + * Added CI configuration for Travis-CI and AppVeyor. + * Added test InterfaceID and ClassID for the COM Test Server project. + * Added more inline documentation (#83). + * Added IEnumVARIANT implementation (#88). + * Added IEnumVARIANT test cases (#99, #100, #101). + * Added support for retrieving `time.Time` from VARIANT (#92). + * Added test case for IUnknown (#64). + * Added test case for IDispatch (#64). + * Added test cases for scalar variants (#64, #76). + +# Version 1.1.1 + + * Fixes for Linux build. + * Fixes for Windows build. + +# Version 1.1.0 + +The change to provide building on all platforms is a new feature. The increase in minor version reflects that and allows those who wish to stay on 1.0.x to continue to do so. Support for 1.0.x will be limited to bug fixes. + + * Move GUID out of variables.go into its own file to make new documentation available. + * Move OleError out of ole.go into its own file to make new documentation available. + * Add documentation to utility functions. + * Add documentation to variant receiver functions. + * Add documentation to ole structures. + * Make variant available to other systems outside of Windows. + * Make OLE structures available to other systems outside of Windows. + +## New Features + + * Library should now be built on all platforms supported by Go. Library will NOOP on any platform that is not Windows. + * More functions are now documented and available on godoc.org. + +# Version 1.0.1 + + 1. Fix package references from repository location change. + +# Version 1.0.0 + +This version is stable enough for use. The COM API is still incomplete, but provides enough functionality for accessing COM servers using IDispatch interface. + +There is no changelog for this version. Check commits for history. diff --git a/vendor/github.com/go-ole/go-ole/README.md b/vendor/github.com/go-ole/go-ole/README.md new file mode 100644 index 00000000000..0ea9db33c79 --- /dev/null +++ b/vendor/github.com/go-ole/go-ole/README.md @@ -0,0 +1,46 @@ +#Go OLE + +[![Build status](https://ci.appveyor.com/api/projects/status/qr0u2sf7q43us9fj?svg=true)](https://ci.appveyor.com/project/jacobsantos/go-ole-jgs28) +[![Build Status](https://travis-ci.org/go-ole/go-ole.svg?branch=master)](https://travis-ci.org/go-ole/go-ole) +[![GoDoc](https://godoc.org/github.com/go-ole/go-ole?status.svg)](https://godoc.org/github.com/go-ole/go-ole) + +Go bindings for Windows COM using shared libraries instead of cgo. + +By Yasuhiro Matsumoto. + +## Install + +To experiment with go-ole, you can just compile and run the example program: + +``` +go get github.com/go-ole/go-ole +cd /path/to/go-ole/ +go test + +cd /path/to/go-ole/example/excel +go run excel.go +``` + +## Continuous Integration + +Continuous integration configuration has been added for both Travis-CI and AppVeyor. You will have to add these to your own account for your fork in order for it to run. + +**Travis-CI** + +Travis-CI was added to check builds on Linux to ensure that `go get` works when cross building. Currently, Travis-CI is not used to test cross-building, but this may be changed in the future. It is also not currently possible to test the library on Linux, since COM API is specific to Windows and it is not currently possible to run a COM server on Linux or even connect to a remote COM server. + +**AppVeyor** + +AppVeyor is used to build on Windows using the (in-development) test COM server. It is currently only used to test the build and ensure that the code works on Windows. It will be used to register a COM server and then run the test cases based on the test COM server. + +The tests currently do run and do pass and this should be maintained with commits. + +##Versioning + +Go OLE uses [semantic versioning](http://semver.org) for version numbers, which is similar to the version contract of the Go language. Which means that the major version will always maintain backwards compatibility with minor versions. Minor versions will only add new additions and changes. Fixes will always be in patch. + +This contract should allow you to upgrade to new minor and patch versions without breakage or modifications to your existing code. Leave a ticket, if there is breakage, so that it could be fixed. + +##LICENSE + +Under the MIT License: http://mattn.mit-license.org/2013 diff --git a/vendor/github.com/go-ole/go-ole/appveyor.yml b/vendor/github.com/go-ole/go-ole/appveyor.yml new file mode 100644 index 00000000000..e66dd31a1db --- /dev/null +++ b/vendor/github.com/go-ole/go-ole/appveyor.yml @@ -0,0 +1,63 @@ +# Notes: +# - Minimal appveyor.yml file is an empty file. All sections are optional. +# - Indent each level of configuration with 2 spaces. Do not use tabs! +# - All section names are case-sensitive. +# - Section names should be unique on each level. + +version: "1.3.0.{build}-alpha-{branch}" + +os: Windows Server 2012 R2 + +branches: + only: + - master + - v1.2 + - v1.1 + - v1.0 + +skip_tags: true + +clone_folder: c:\gopath\src\github.com\go-ole\go-ole + +environment: + GOPATH: c:\gopath + matrix: + - GOARCH: amd64 + GOVERSION: 1.4 + GOROOT: c:\go + DOWNLOADPLATFORM: "x64" + +install: + - choco install mingw + - SET PATH=c:\tools\mingw64\bin;%PATH% + # - Download COM Server + - ps: Start-FileDownload "https://github.com/go-ole/test-com-server/releases/download/v1.0.2/test-com-server-${env:DOWNLOADPLATFORM}.zip" + - 7z e test-com-server-%DOWNLOADPLATFORM%.zip -oc:\gopath\src\github.com\go-ole\go-ole > NUL + - c:\gopath\src\github.com\go-ole\go-ole\build\register-assembly.bat + # - set + - go version + - go env + - c:\gopath\src\github.com\go-ole\go-ole\build\compile-go.bat + - go tool dist install -v cmd/8a + - go tool dist install -v cmd/8c + - go tool dist install -v cmd/8g + - go tool dist install -v cmd/8l + - go tool dist install -v cmd/6a + - go tool dist install -v cmd/6c + - go tool dist install -v cmd/6g + - go tool dist install -v cmd/6l + - go get -u golang.org/x/tools/cmd/cover + - go get -u golang.org/x/tools/cmd/godoc + - go get -u golang.org/x/tools/cmd/stringer + +build_script: + - cd c:\gopath\src\github.com\go-ole\go-ole + - go get -v -t ./... + - go build + - go test -v -cover ./... + +# disable automatic tests +test: off + +# disable deployment +deploy: off diff --git a/vendor/github.com/go-ole/go-ole/ole.go b/vendor/github.com/go-ole/go-ole/ole.go index b92b4ea189f..e2ae4f4bbfe 100644 --- a/vendor/github.com/go-ole/go-ole/ole.go +++ b/vendor/github.com/go-ole/go-ole/ole.go @@ -26,6 +26,16 @@ type EXCEPINFO struct { scode uint32 } +// WCode return wCode in EXCEPINFO. +func (e EXCEPINFO) WCode() uint16 { + return e.wCode +} + +// SCODE return scode in EXCEPINFO. +func (e EXCEPINFO) SCODE() uint32 { + return e.scode +} + // String convert EXCEPINFO to string. func (e EXCEPINFO) String() string { var src, desc, hlp string diff --git a/vendor/github.com/go-ole/go-ole/variant_s390x.go b/vendor/github.com/go-ole/go-ole/variant_s390x.go new file mode 100644 index 00000000000..9874ca66b4f --- /dev/null +++ b/vendor/github.com/go-ole/go-ole/variant_s390x.go @@ -0,0 +1,12 @@ +// +build s390x + +package ole + +type VARIANT struct { + VT VT // 2 + wReserved1 uint16 // 4 + wReserved2 uint16 // 6 + wReserved3 uint16 // 8 + Val int64 // 16 + _ [8]byte // 24 +} diff --git a/vendor/github.com/shirou/gopsutil/Makefile b/vendor/github.com/shirou/gopsutil/Makefile index 2c1bac80b7b..987af227f3f 100644 --- a/vendor/github.com/shirou/gopsutil/Makefile +++ b/vendor/github.com/shirou/gopsutil/Makefile @@ -15,7 +15,7 @@ build_test: ## test only buildable # Supported operating systems GOOS=linux go test ./... | $(BUILD_FAIL_PATTERN) GOOS=freebsd go test ./... | $(BUILD_FAIL_PATTERN) - GOOS=openbsd go test ./... | $(BUILD_FAIL_PATTERN) +# GOOS=openbsd go test ./... | $(BUILD_FAIL_PATTERN) CGO_ENABLED=0 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN) CGO_ENABLED=1 GOOS=darwin go test ./... | $(BUILD_FAIL_PATTERN) GOOS=windows go test ./... | $(BUILD_FAIL_PATTERN) diff --git a/vendor/github.com/shirou/gopsutil/README.rst b/vendor/github.com/shirou/gopsutil/README.rst index 32759702ba6..18ee9bacc92 100644 --- a/vendor/github.com/shirou/gopsutil/README.rst +++ b/vendor/github.com/shirou/gopsutil/README.rst @@ -14,27 +14,22 @@ This is a port of psutil (http://pythonhosted.org/psutil/). The challenge is por psutil functions on some architectures. -.. highlights:: Breaking Changes! +Breaking Changes! golang 1.8 is required +------------------------------------------- - Breaking changes is introduced at v2. See `issue 174 `_ . - - -Migrating to v2 -------------------------- - -On gopsutil itself, `v2migration.sh `_ is used for migration. It can not be commonly used, but it may help you with migration. +After v2.17.04, golang 1.8 is required to build. Tag semantics -^^^^^^^^^^^^^^^ +------------------------- gopsutil tag policy is almost same as Semantic Versioning, but automatically increase like Ubuntu versioning. -for example, `v2.16.10` means +for example, `v2.17.04` means - v2: major version -- 16: release year, 2016 -- 10: release month +- 17: release year, 2017 +- 04: release month gopsutil aims to keep backwards-compatiblity until major version change. @@ -206,7 +201,7 @@ pid x x x x x ppid x x x x x name x x x x x cmdline x x x -create_time x +create_time x x status x x x x cwd x exe x x x x @@ -228,16 +223,16 @@ suspend x x x x resume x x x x terminate x x x x x kill x x x x -username x +username x x x x x ionice -rlimit -num_handlres +rlimit x +num_handlers threads cpu_percent x x x cpu_affinity memory_percent -parent x x x -children x x x x +parent x x x x +children x x x x x connections x x x is_running ================ ===== ======= ======= ====== ======= diff --git a/vendor/github.com/shirou/gopsutil/circle.yml b/vendor/github.com/shirou/gopsutil/circle.yml index ad8c43d558d..541cded89b4 100644 --- a/vendor/github.com/shirou/gopsutil/circle.yml +++ b/vendor/github.com/shirou/gopsutil/circle.yml @@ -1,6 +1,8 @@ machine: timezone: Asia/Tokyo + pre: + - sudo chown -R ubuntu:ubuntu /usr/local/go/pkg/ test: override: - GOOS=linux GOARCH=amd64 go test -v ./... diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu.go b/vendor/github.com/shirou/gopsutil/cpu/cpu.go index 2bd5c8d4385..f5bf315fe2f 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu.go @@ -130,8 +130,9 @@ func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) { return ret, nil } -//Percent calculates the percentage of cpu used either per CPU or combined. -//If an interval of 0 is given it will compare the current cpu times against the last call. +// Percent calculates the percentage of cpu used either per CPU or combined. +// If an interval of 0 is given it will compare the current cpu times against the last call. +// Returns one value per cpu, or a single value if percpu is set to false. func Percent(interval time.Duration, percpu bool) ([]float64, error) { if interval <= 0 { return percentUsedFromLastCall(percpu) diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_fallback.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_fallback.go index 8f72b78430f..8e09ccb4e54 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_fallback.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_fallback.go @@ -3,8 +3,6 @@ package cpu import ( - "time" - "github.com/shirou/gopsutil/internal/common" ) diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd.go index 877fe7e7ac6..7d0321f7934 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_freebsd.go @@ -146,7 +146,7 @@ func Info() ([]InfoStat, error) { func parseDmesgBoot(fileName string) (InfoStat, int, error) { c := InfoStat{} lines, _ := common.ReadLines(fileName) - var cpuNum int + cpuNum := 1 // default cpu num is 1 for _, line := range lines { if matches := cpuEnd.FindStringSubmatch(line); matches != nil { break diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go index 6bd36cdf889..48e45da3923 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_linux.go @@ -33,18 +33,15 @@ func Times(percpu bool) ([]TimesStat, error) { filename := common.HostProc("stat") var lines = []string{} if percpu { - var startIdx uint = 1 - for { - linen, _ := common.ReadLinesOffsetN(filename, startIdx, 1) - if len(linen) == 0 { - break - } - line := linen[0] + statlines, err := common.ReadLines(filename) + if err != nil || len(statlines) < 2 { + return []TimesStat{}, nil + } + for _, line := range statlines[1:] { if !strings.HasPrefix(line, "cpu") { break } lines = append(lines, line) - startIdx++ } } else { lines, _ = common.ReadLinesOffsetN(filename, 0, 1) @@ -83,24 +80,19 @@ func finishCPUInfo(c *InfoStat) error { // of the value from /proc/cpuinfo because we want to report the maximum // clock-speed of the CPU for c.Mhz, matching the behaviour of Windows lines, err = common.ReadLines(sysCPUPath(c.CPU, "cpufreq/cpuinfo_max_freq")) - // if we encounter errors below but has a value from parsing /proc/cpuinfo - // then we ignore the error + // if we encounter errors below such as there are no cpuinfo_max_freq file, + // we just ignore. so let Mhz is 0. if err != nil { - if c.Mhz == 0 { - return err - } else { - return nil - } + return nil } value, err = strconv.ParseFloat(lines[0], 64) if err != nil { - if c.Mhz == 0 { - return err - } else { - return nil - } + return nil } c.Mhz = value / 1000.0 // value is in kHz + if c.Mhz > 9999 { + c.Mhz = c.Mhz / 1000.0 // value in Hz + } return nil } @@ -116,6 +108,7 @@ func Info() ([]InfoStat, error) { lines, _ := common.ReadLines(filename) var ret []InfoStat + var processorName string c := InfoStat{CPU: -1, Cores: 1} for _, line := range lines { @@ -127,6 +120,8 @@ func Info() ([]InfoStat, error) { value := strings.TrimSpace(fields[1]) switch key { + case "Processor": + processorName = value case "processor": if c.CPU >= 0 { err := finishCPUInfo(&c) @@ -135,7 +130,7 @@ func Info() ([]InfoStat, error) { } ret = append(ret, c) } - c = InfoStat{Cores: 1} + c = InfoStat{Cores: 1, ModelName: processorName} t, err := strconv.ParseInt(value, 10, 64) if err != nil { return ret, err diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_openbsd.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_openbsd.go index c59bf9caa9e..03aae6e99fe 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_openbsd.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_openbsd.go @@ -9,9 +9,9 @@ import ( "os/exec" "strconv" "strings" - "syscall" "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/unix" ) // sys/sched.h @@ -100,7 +100,7 @@ func Info() ([]InfoStat, error) { c := InfoStat{} - v, err := syscall.Sysctl("hw.model") + v, err := unix.Sysctl("hw.model") if err != nil { return nil, err } diff --git a/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go b/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go index a32d2419af8..b5bf8258fdd 100644 --- a/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go +++ b/vendor/github.com/shirou/gopsutil/cpu/cpu_windows.go @@ -4,12 +4,11 @@ package cpu import ( "fmt" - "syscall" "unsafe" "github.com/StackExchange/wmi" - "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/windows" ) type Win32_Processor struct { @@ -23,10 +22,34 @@ type Win32_Processor struct { MaxClockSpeed uint32 } -// TODO: Get percpu +// Win32_PerfFormattedData_Counters_ProcessorInformation stores instance value of the perf counters +type Win32_PerfFormattedData_Counters_ProcessorInformation struct { + Name string + PercentDPCTime uint64 + PercentIdleTime uint64 + PercentUserTime uint64 + PercentProcessorTime uint64 + PercentInterruptTime uint64 + PercentPriorityTime uint64 + PercentPrivilegedTime uint64 + InterruptsPerSec uint32 + ProcessorFrequency uint32 + DPCRate uint32 +} + +// Win32_PerfFormattedData_PerfOS_System struct to have count of processes and processor queue length +type Win32_PerfFormattedData_PerfOS_System struct { + Processes uint32 + ProcessorQueueLength uint32 +} + +// Times returns times stat per cpu and combined for all CPUs func Times(percpu bool) ([]TimesStat, error) { - var ret []TimesStat + if percpu { + return perCPUTimes() + } + var ret []TimesStat var lpIdleTime common.FILETIME var lpKernelTime common.FILETIME var lpUserTime common.FILETIME @@ -35,7 +58,7 @@ func Times(percpu bool) ([]TimesStat, error) { uintptr(unsafe.Pointer(&lpKernelTime)), uintptr(unsafe.Pointer(&lpUserTime))) if r == 0 { - return ret, syscall.GetLastError() + return ret, windows.GetLastError() } LOT := float64(0.0000001) @@ -46,6 +69,7 @@ func Times(percpu bool) ([]TimesStat, error) { system := (kernel - idle) ret = append(ret, TimesStat{ + CPU: "cpu-total", Idle: float64(idle), User: float64(user), System: float64(system), @@ -84,3 +108,41 @@ func Info() ([]InfoStat, error) { return ret, nil } + +// PerfInfo returns the performance counter's instance value for ProcessorInformation. +// Name property is the key by which overall, per cpu and per core metric is known. +func PerfInfo() ([]Win32_PerfFormattedData_Counters_ProcessorInformation, error) { + var ret []Win32_PerfFormattedData_Counters_ProcessorInformation + q := wmi.CreateQuery(&ret, "") + err := wmi.Query(q, &ret) + return ret, err +} + +// ProcInfo returns processes count and processor queue length in the system. +// There is a single queue for processor even on multiprocessors systems. +func ProcInfo() ([]Win32_PerfFormattedData_PerfOS_System, error) { + var ret []Win32_PerfFormattedData_PerfOS_System + q := wmi.CreateQuery(&ret, "") + err := wmi.Query(q, &ret) + return ret, err +} + +// perCPUTimes returns times stat per cpu, per core and overall for all CPUs +func perCPUTimes() ([]TimesStat, error) { + var ret []TimesStat + stats, err := PerfInfo() + if err != nil { + return nil, err + } + for _, v := range stats { + c := TimesStat{ + CPU: v.Name, + User: float64(v.PercentUserTime), + System: float64(v.PercentPrivilegedTime), + Idle: float64(v.PercentIdleTime), + Irq: float64(v.PercentInterruptTime), + } + ret = append(ret, c) + } + return ret, nil +} diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_darwin.go b/vendor/github.com/shirou/gopsutil/disk/disk_darwin.go index 1ccb3303194..76672c16ce1 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_darwin.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_darwin.go @@ -4,10 +4,10 @@ package disk import ( "path" - "syscall" "unsafe" "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/unix" ) func Partitions(all bool) ([]PartitionStat, error) { @@ -87,10 +87,6 @@ func Partitions(all bool) ([]PartitionStat, error) { return ret, nil } -func IOCounters() (map[string]IOCountersStat, error) { - return nil, common.ErrNotImplementedError -} - func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { var _p0 unsafe.Pointer var bufsize uintptr @@ -98,7 +94,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { _p0 = unsafe.Pointer(&buf[0]) bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf)) } - r0, _, e1 := syscall.Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags)) + r0, _, e1 := unix.Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags)) n = int(r0) if e1 != 0 { err = e1 @@ -106,6 +102,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) { return } -func getFsType(stat syscall.Statfs_t) string { +func getFsType(stat unix.Statfs_t) string { return common.IntToString(stat.Fstypename[:]) } diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_darwin.h b/vendor/github.com/shirou/gopsutil/disk/disk_darwin.h new file mode 100644 index 00000000000..d0fe514e351 --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/disk/disk_darwin.h @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include + +// The iterator of all things disk. Allocated by StartIOCounterFetch, released +// by EndIOCounterFetch. +static io_iterator_t diskIter; + +// Begins fetching IO counters. +// +// Returns 1 if the fetch started successfully, false otherwise. +// +// If the fetch was started successfully, you must call EndIOCounterFetch once +// done to release resources. +int StartIOCounterFetch() +{ + if (IOServiceGetMatchingServices(kIOMasterPortDefault, + IOServiceMatching(kIOMediaClass), + &diskIter) != kIOReturnSuccess) { + return 0; + } + + return 1; +} + +// Releases resources from fetching IO counters. +void EndIOCounterFetch() +{ + IOObjectRelease(diskIter); +} + +// The current disk entry of interest. Allocated by FetchNextDisk(), released by +// ReadDiskInfo(). +static io_registry_entry_t diskEntry; + +// The parent of diskEntry. Same lifetimes. +static io_registry_entry_t parentEntry; + +// Fetches the next disk. Note that a disk entry is allocated, and will be held +// until it is processed and freed by ReadDiskInfo. +int FetchNextDisk() +{ + while ((diskEntry = IOIteratorNext(diskIter)) != 0) { + // We are iterating IOMedia. We need to get the parent too (IOBSD). + if (IORegistryEntryGetParentEntry(diskEntry, kIOServicePlane, &parentEntry) != kIOReturnSuccess) { + // something is wrong... + IOObjectRelease(diskEntry); + continue; + } + + if (!IOObjectConformsTo(parentEntry, "IOBlockStorageDriver")) { + // no use to us, try the next disk + IOObjectRelease(diskEntry); + IOObjectRelease(parentEntry); + continue; + } + + // Got a disk OK. + return 1; + } + + // No more disks. + return 0; +} + +// Reads the current disk (from iteration) info into DiskInfo struct. +// Once done, all resources from the current iteration of reading are freed, +// ready for FetchNextDisk() to be called again. +int ReadDiskInfo(DiskInfo *info) +{ + // Parent props. Allocated by us. + CFDictionaryRef parentProps = NULL; + + // Disk props. Allocated by us. + CFDictionaryRef diskProps = NULL; + + // Disk stats, fetched by us, but not allocated by us. + CFDictionaryRef stats = NULL; + + if (IORegistryEntryCreateCFProperties(diskEntry, (CFMutableDictionaryRef *)&parentProps, + kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) + { + // can't get parent props, give up + CFRelease(parentProps); + IOObjectRelease(diskEntry); + IOObjectRelease(parentEntry); + return -1; + } + + if (IORegistryEntryCreateCFProperties(parentEntry, (CFMutableDictionaryRef *)&diskProps, + kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) + { + // can't get disk props, give up + CFRelease(parentProps); + CFRelease(diskProps); + IOObjectRelease(diskEntry); + IOObjectRelease(parentEntry); + return -1; + } + + // Start fetching + CFStringRef cfDiskName = (CFStringRef)CFDictionaryGetValue(parentProps, CFSTR(kIOBSDNameKey)); + CFStringGetCString(cfDiskName, info->DiskName, MAX_DISK_NAME, CFStringGetSystemEncoding()); + stats = (CFDictionaryRef)CFDictionaryGetValue( diskProps, CFSTR(kIOBlockStorageDriverStatisticsKey)); + + if (stats == NULL) { + // stat fetch failed... + CFRelease(parentProps); + CFRelease(diskProps); + IOObjectRelease(parentEntry); + IOObjectRelease(diskEntry); + return -1; + } + + CFNumberRef cfnum; + + if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) { + CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->Reads); + } else { + info->Reads = 0; + } + + if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) { + CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->Writes); + } else { + info->Writes = 0; + } + + if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) { + CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->ReadBytes); + } else { + info->ReadBytes = 0; + } + + if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) { + CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->WriteBytes); + } else { + info->WriteBytes = 0; + } + + if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) { + CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->ReadTime); + } else { + info->ReadTime = 0; + } + if ((cfnum = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) { + CFNumberGetValue(cfnum, kCFNumberSInt64Type, &info->WriteTime); + } else { + info->WriteTime = 0; + } + + // note: read/write time are in ns, but we want ms. + info->ReadTime = info->ReadTime / 1000 / 1000; + info->WriteTime = info->WriteTime / 1000 / 1000; + + CFRelease(parentProps); + CFRelease(diskProps); + IOObjectRelease(parentEntry); + IOObjectRelease(diskEntry); + return 0; +} + diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_darwin_cgo.go b/vendor/github.com/shirou/gopsutil/disk/disk_darwin_cgo.go new file mode 100644 index 00000000000..f75ac9b280c --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/disk/disk_darwin_cgo.go @@ -0,0 +1,90 @@ +// +build darwin +// +build cgo + +package disk + +/* +#cgo LDFLAGS: -lobjc -framework Foundation -framework IOKit +#include + +// ### enough? +const int MAX_DISK_NAME = 100; + +typedef struct +{ + char DiskName[MAX_DISK_NAME]; + int64_t Reads; + int64_t Writes; + int64_t ReadBytes; + int64_t WriteBytes; + int64_t ReadTime; + int64_t WriteTime; +} DiskInfo; + +#include "disk_darwin.h" +*/ +import "C" + +import ( + "errors" + "strings" + "unsafe" + + "github.com/shirou/gopsutil/internal/common" +) + +func IOCounters(names ...string) (map[string]IOCountersStat, error) { + if C.StartIOCounterFetch() == 0 { + return nil, errors.New("Unable to fetch disk list") + } + + // Clean up when we are done. + defer C.EndIOCounterFetch() + ret := make(map[string]IOCountersStat, 0) + + for { + res := C.FetchNextDisk() + if res == -1 { + return nil, errors.New("Unable to fetch disk information") + } else if res == 0 { + break // done + } + + di := C.DiskInfo{} + if C.ReadDiskInfo((*C.DiskInfo)(unsafe.Pointer(&di))) == -1 { + return nil, errors.New("Unable to fetch disk properties") + } + + // Used to only get the necessary part of the C string. + isRuneNull := func(r rune) bool { + return r == '\u0000' + } + + // Map from the darwin-specific C struct to the Go type + // + // ### missing: IopsInProgress, WeightedIO, MergedReadCount, + // MergedWriteCount, SerialNumber + // IOKit can give us at least the serial number I think... + d := IOCountersStat{ + // Note: The Go type wants unsigned values, but CFNumberGetValue + // doesn't appear to be able to give us unsigned values. So, we + // cast, and hope for the best. + ReadBytes: uint64(di.ReadBytes), + WriteBytes: uint64(di.WriteBytes), + ReadCount: uint64(di.Reads), + WriteCount: uint64(di.Writes), + ReadTime: uint64(di.ReadTime), + WriteTime: uint64(di.WriteTime), + IoTime: uint64(di.ReadTime + di.WriteTime), + Name: strings.TrimFunc(C.GoStringN(&di.DiskName[0], C.MAX_DISK_NAME), isRuneNull), + } + + if len(names) > 0 && !common.StringsHas(names, d.Name) { + continue + } + + ret[d.Name] = d + } + + return ret, nil +} diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_darwin_nocgo.go b/vendor/github.com/shirou/gopsutil/disk/disk_darwin_nocgo.go new file mode 100644 index 00000000000..60fd7a6cebc --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/disk/disk_darwin_nocgo.go @@ -0,0 +1,10 @@ +// +build darwin +// +build !cgo + +package disk + +import "github.com/shirou/gopsutil/internal/common" + +func IOCounters(names ...string) (map[string]IOCountersStat, error) { + return nil, common.ErrNotImplementedError +} diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_fallback.go b/vendor/github.com/shirou/gopsutil/disk/disk_fallback.go index 6fb01a986c0..db521842d82 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_fallback.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_fallback.go @@ -4,7 +4,7 @@ package disk import "github.com/shirou/gopsutil/internal/common" -func IOCounters() (map[string]IOCountersStat, error) { +func IOCounters(names ...string) (map[string]IOCountersStat, error) { return nil, common.ErrNotImplementedError } diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_freebsd.go b/vendor/github.com/shirou/gopsutil/disk/disk_freebsd.go index 6e76f31f274..8cd5aef5b6c 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_freebsd.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_freebsd.go @@ -7,9 +7,10 @@ import ( "encoding/binary" "path" "strconv" - "syscall" "unsafe" + "golang.org/x/sys/unix" + "github.com/shirou/gopsutil/internal/common" ) @@ -17,7 +18,7 @@ func Partitions(all bool) ([]PartitionStat, error) { var ret []PartitionStat // get length - count, err := syscall.Getfsstat(nil, MNT_WAIT) + count, err := unix.Getfsstat(nil, MNT_WAIT) if err != nil { return ret, err } @@ -94,12 +95,12 @@ func Partitions(all bool) ([]PartitionStat, error) { return ret, nil } -func IOCounters() (map[string]IOCountersStat, error) { +func IOCounters(names ...string) (map[string]IOCountersStat, error) { // statinfo->devinfo->devstat // /usr/include/devinfo.h ret := make(map[string]IOCountersStat) - r, err := syscall.Sysctl("kern.devstat.all") + r, err := unix.Sysctl("kern.devstat.all") if err != nil { return nil, err } @@ -119,6 +120,10 @@ func IOCounters() (map[string]IOCountersStat, error) { un := strconv.Itoa(int(d.Unit_number)) name := common.IntToString(d.Device_name[:]) + un + if len(names) > 0 && !common.StringsHas(names, name) { + continue + } + ds := IOCountersStat{ ReadCount: d.Operations[DEVSTAT_READ], WriteCount: d.Operations[DEVSTAT_WRITE], @@ -151,7 +156,7 @@ func Getfsstat(buf []Statfs, flags int) (n int, err error) { _p0 = unsafe.Pointer(&buf[0]) bufsize = unsafe.Sizeof(Statfs{}) * uintptr(len(buf)) } - r0, _, e1 := syscall.Syscall(syscall.SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags)) + r0, _, e1 := unix.Syscall(unix.SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags)) n = int(r0) if e1 != 0 { err = e1 @@ -171,6 +176,6 @@ func parseDevstat(buf []byte) (Devstat, error) { return ds, nil } -func getFsType(stat syscall.Statfs_t) string { +func getFsType(stat unix.Statfs_t) string { return common.IntToString(stat.Fstypename[:]) } diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_linux.go b/vendor/github.com/shirou/gopsutil/disk/disk_linux.go index 51f17cd415b..f31c3911529 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_linux.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_linux.go @@ -7,7 +7,8 @@ import ( "os/exec" "strconv" "strings" - "syscall" + + "golang.org/x/sys/unix" "github.com/shirou/gopsutil/internal/common" ) @@ -214,10 +215,8 @@ var fsTypeMap = map[int64]string{ // Partitions returns disk partitions. If all is false, returns // physical devices only (e.g. hard disks, cd-rom drives, USB keys) // and ignore all others (e.g. memory partitions such as /dev/shm) -// -// should use setmntent(3) but this implement use /etc/mtab file func Partitions(all bool) ([]PartitionStat, error) { - filename := common.HostEtc("mtab") + filename := common.HostProc("self/mounts") lines, err := common.ReadLines(filename) if err != nil { return nil, err @@ -272,7 +271,7 @@ func getFileSystems() ([]string, error) { return ret, nil } -func IOCounters() (map[string]IOCountersStat, error) { +func IOCounters(names ...string) (map[string]IOCountersStat, error) { filename := common.HostProc("diskstats") lines, err := common.ReadLines(filename) if err != nil { @@ -288,6 +287,11 @@ func IOCounters() (map[string]IOCountersStat, error) { continue } name := fields[2] + + if len(names) > 0 && !common.StringsHas(names, name) { + continue + } + reads, err := strconv.ParseUint((fields[3]), 10, 64) if err != nil { return ret, err @@ -383,7 +387,7 @@ func GetDiskSerialNumber(name string) string { return "" } -func getFsType(stat syscall.Statfs_t) string { +func getFsType(stat unix.Statfs_t) string { t := int64(stat.Type) ret, ok := fsTypeMap[t] if !ok { diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_openbsd.go b/vendor/github.com/shirou/gopsutil/disk/disk_openbsd.go index 2129b2b6adf..d1705eaf896 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_openbsd.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_openbsd.go @@ -6,17 +6,17 @@ import ( "bytes" "encoding/binary" "path" - "syscall" "unsafe" "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/unix" ) func Partitions(all bool) ([]PartitionStat, error) { var ret []PartitionStat // get length - count, err := syscall.Getfsstat(nil, MNT_WAIT) + count, err := unix.Getfsstat(nil, MNT_WAIT) if err != nil { return ret, err } @@ -63,10 +63,10 @@ func Partitions(all bool) ([]PartitionStat, error) { return ret, nil } -func IOCounters() (map[string]IOCountersStat, error) { +func IOCounters(names ...string) (map[string]IOCountersStat, error) { ret := make(map[string]IOCountersStat) - r, err := syscall.Sysctl("hw.diskstats") + r, err := unix.Sysctl("hw.diskstats") if err != nil { return nil, err } @@ -84,6 +84,10 @@ func IOCounters() (map[string]IOCountersStat, error) { } name := common.IntToString(d.Name[:]) + if len(names) > 0 && !common.StringsHas(names, name) { + continue + } + ds := IOCountersStat{ ReadCount: d.Rxfer, WriteCount: d.Wxfer, @@ -108,7 +112,7 @@ func Getfsstat(buf []Statfs, flags int) (n int, err error) { _p0 = unsafe.Pointer(&buf[0]) bufsize = unsafe.Sizeof(Statfs{}) * uintptr(len(buf)) } - r0, _, e1 := syscall.Syscall(syscall.SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags)) + r0, _, e1 := unix.Syscall(unix.SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags)) n = int(r0) if e1 != 0 { err = e1 @@ -129,8 +133,8 @@ func parseDiskstats(buf []byte) (Diskstats, error) { } func Usage(path string) (*UsageStat, error) { - stat := syscall.Statfs_t{} - err := syscall.Statfs(path, &stat) + stat := unix.Statfs_t{} + err := unix.Statfs(path, &stat) if err != nil { return nil, err } @@ -153,6 +157,6 @@ func Usage(path string) (*UsageStat, error) { return ret, nil } -func getFsType(stat syscall.Statfs_t) string { +func getFsType(stat unix.Statfs_t) string { return common.IntToString(stat.F_fstypename[:]) } diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_unix.go b/vendor/github.com/shirou/gopsutil/disk/disk_unix.go index f0616c30aaa..8520829fa79 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_unix.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_unix.go @@ -2,11 +2,14 @@ package disk -import "syscall" +import "golang.org/x/sys/unix" +// Usage returns a file system usage. path is a filessytem path such +// as "/", not device file path like "/dev/vda1". If you want to use +// a return value of disk.Partitions, use "Mountpoint" not "Device". func Usage(path string) (*UsageStat, error) { - stat := syscall.Statfs_t{} - err := syscall.Statfs(path, &stat) + stat := unix.Statfs_t{} + err := unix.Statfs(path, &stat) if err != nil { return nil, err } diff --git a/vendor/github.com/shirou/gopsutil/disk/disk_windows.go b/vendor/github.com/shirou/gopsutil/disk/disk_windows.go index b3a30d69f84..6cc22a29645 100644 --- a/vendor/github.com/shirou/gopsutil/disk/disk_windows.go +++ b/vendor/github.com/shirou/gopsutil/disk/disk_windows.go @@ -4,12 +4,11 @@ package disk import ( "bytes" - "syscall" "unsafe" "github.com/StackExchange/wmi" - "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/windows" ) var ( @@ -43,7 +42,7 @@ func Usage(path string) (*UsageStat, error) { lpTotalNumberOfBytes := int64(0) lpTotalNumberOfFreeBytes := int64(0) diskret, _, err := procGetDiskFreeSpaceExW.Call( - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))), + uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(path))), uintptr(unsafe.Pointer(&lpFreeBytesAvailable)), uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)), uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes))) @@ -79,20 +78,20 @@ func Partitions(all bool) ([]PartitionStat, error) { if path == "A:" || path == "B:" { // skip floppy drives continue } - typepath, _ := syscall.UTF16PtrFromString(path) + typepath, _ := windows.UTF16PtrFromString(path) typeret, _, _ := procGetDriveType.Call(uintptr(unsafe.Pointer(typepath))) if typeret == 0 { - return ret, syscall.GetLastError() + return ret, windows.GetLastError() } - // 2: DRIVE_REMOVABLE 3: DRIVE_FIXED 5: DRIVE_CDROM + // 2: DRIVE_REMOVABLE 3: DRIVE_FIXED 4: DRIVE_REMOTE 5: DRIVE_CDROM - if typeret == 2 || typeret == 3 || typeret == 5 { + if typeret == 2 || typeret == 3 || typeret == 4 || typeret == 5 { lpVolumeNameBuffer := make([]byte, 256) lpVolumeSerialNumber := int64(0) lpMaximumComponentLength := int64(0) lpFileSystemFlags := int64(0) lpFileSystemNameBuffer := make([]byte, 256) - volpath, _ := syscall.UTF16PtrFromString(string(v) + ":/") + volpath, _ := windows.UTF16PtrFromString(string(v) + ":/") driveret, _, err := provGetVolumeInformation.Call( uintptr(unsafe.Pointer(volpath)), uintptr(unsafe.Pointer(&lpVolumeNameBuffer[0])), @@ -103,7 +102,7 @@ func Partitions(all bool) ([]PartitionStat, error) { uintptr(unsafe.Pointer(&lpFileSystemNameBuffer[0])), uintptr(len(lpFileSystemNameBuffer))) if driveret == 0 { - if typeret == 5 { + if typeret == 5 || typeret == 2 { continue //device is not ready will happen if there is no disk in the drive } return ret, err @@ -129,7 +128,7 @@ func Partitions(all bool) ([]PartitionStat, error) { return ret, nil } -func IOCounters() (map[string]IOCountersStat, error) { +func IOCounters(names ...string) (map[string]IOCountersStat, error) { ret := make(map[string]IOCountersStat, 0) var dst []Win32_PerfFormattedData @@ -141,6 +140,11 @@ func IOCounters() (map[string]IOCountersStat, error) { if len(d.Name) > 3 { // not get _Total or Harddrive continue } + + if len(names) > 0 && !common.StringsHas(names, d.Name) { + continue + } + ret[d.Name] = IOCountersStat{ Name: d.Name, ReadCount: uint64(d.AvgDiskReadQueueLength), diff --git a/vendor/github.com/shirou/gopsutil/host/host.go b/vendor/github.com/shirou/gopsutil/host/host.go index 5a800a7d351..a256a6c8ea0 100644 --- a/vendor/github.com/shirou/gopsutil/host/host.go +++ b/vendor/github.com/shirou/gopsutil/host/host.go @@ -6,10 +6,7 @@ import ( "github.com/shirou/gopsutil/internal/common" ) -var ( - invoke common.Invoker - cachedBootTime = uint64(0) -) +var invoke common.Invoker func init() { invoke = common.Invoke{} @@ -39,6 +36,11 @@ type UserStat struct { Started int `json:"started"` } +type TemperatureStat struct { + SensorKey string `json:"sensorKey"` + Temperature float64 `json:"sensorTemperature"` +} + func (h InfoStat) String() string { s, _ := json.Marshal(h) return string(s) @@ -48,3 +50,8 @@ func (u UserStat) String() string { s, _ := json.Marshal(u) return string(s) } + +func (t TemperatureStat) String() string { + s, _ := json.Marshal(t) + return string(s) +} diff --git a/vendor/github.com/shirou/gopsutil/host/host_darwin.go b/vendor/github.com/shirou/gopsutil/host/host_darwin.go index 7b68d74d282..c5b24b853df 100644 --- a/vendor/github.com/shirou/gopsutil/host/host_darwin.go +++ b/vendor/github.com/shirou/gopsutil/host/host_darwin.go @@ -11,6 +11,7 @@ import ( "runtime" "strconv" "strings" + "sync/atomic" "time" "unsafe" @@ -32,12 +33,19 @@ func Info() (*InfoStat, error) { ret.Hostname = hostname } - platform, family, pver, version, err := PlatformInformation() + uname, err := exec.LookPath("uname") + if err == nil { + out, err := invoke.Command(uname, "-r") + if err == nil { + ret.KernelVersion = strings.ToLower(strings.TrimSpace(string(out))) + } + } + + platform, family, pver, err := PlatformInformation() if err == nil { ret.Platform = platform ret.PlatformFamily = family ret.PlatformVersion = pver - ret.KernelVersion = version } system, role, err := Virtualization() @@ -65,9 +73,13 @@ func Info() (*InfoStat, error) { return ret, nil } +// cachedBootTime must be accessed via atomic.Load/StoreUint64 +var cachedBootTime uint64 + func BootTime() (uint64, error) { - if cachedBootTime != 0 { - return cachedBootTime, nil + t := atomic.LoadUint64(&cachedBootTime) + if t != 0 { + return t, nil } values, err := common.DoSysctrl("kern.boottime") if err != nil { @@ -79,9 +91,10 @@ func BootTime() (uint64, error) { if err != nil { return 0, err } - cachedBootTime = uint64(boottime) + t = uint64(boottime) + atomic.StoreUint64(&cachedBootTime, t) - return cachedBootTime, nil + return t, nil } func uptime(boot uint64) uint64 { @@ -140,19 +153,18 @@ func Users() ([]UserStat, error) { } -func PlatformInformation() (string, string, string, string, error) { +func PlatformInformation() (string, string, string, error) { platform := "" family := "" - version := "" pver := "" sw_vers, err := exec.LookPath("sw_vers") if err != nil { - return "", "", "", "", err + return "", "", "", err } uname, err := exec.LookPath("uname") if err != nil { - return "", "", "", "", err + return "", "", "", err } out, err := invoke.Command(uname, "-s") @@ -165,12 +177,7 @@ func PlatformInformation() (string, string, string, string, error) { pver = strings.ToLower(strings.TrimSpace(string(out))) } - out, err = invoke.Command(uname, "-r") - if err == nil { - version = strings.ToLower(strings.TrimSpace(string(out))) - } - - return platform, family, pver, version, nil + return platform, family, pver, nil } func Virtualization() (string, string, error) { diff --git a/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go b/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go new file mode 100644 index 00000000000..be5e18b88b0 --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/host/host_darwin_cgo.go @@ -0,0 +1,46 @@ +// +build darwin +// +build cgo + +package host + +// #cgo LDFLAGS: -framework IOKit +// #include "include/smc.c" +import "C" + +func SensorsTemperatures() ([]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 new file mode 100644 index 00000000000..0205888c32a --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/host/host_darwin_nocgo.go @@ -0,0 +1,10 @@ +// +build darwin +// +build !cgo + +package host + +import "github.com/shirou/gopsutil/internal/common" + +func SensorsTemperatures() ([]TemperatureStat, error) { + return []TemperatureStat{}, common.ErrNotImplementedError +} diff --git a/vendor/github.com/shirou/gopsutil/host/host_freebsd.go b/vendor/github.com/shirou/gopsutil/host/host_freebsd.go index d8bd6fcc2cf..e7924f90dbc 100644 --- a/vendor/github.com/shirou/gopsutil/host/host_freebsd.go +++ b/vendor/github.com/shirou/gopsutil/host/host_freebsd.go @@ -11,6 +11,7 @@ import ( "runtime" "strconv" "strings" + "sync/atomic" "time" "unsafe" @@ -68,9 +69,13 @@ func Info() (*InfoStat, error) { return ret, nil } +// cachedBootTime must be accessed via atomic.Load/StoreUint64 +var cachedBootTime uint64 + func BootTime() (uint64, error) { - if cachedBootTime != 0 { - return cachedBootTime, nil + t := atomic.LoadUint64(&cachedBootTime) + if t != 0 { + return t, nil } values, err := common.DoSysctrl("kern.boottime") if err != nil { @@ -83,9 +88,10 @@ func BootTime() (uint64, error) { if err != nil { return 0, err } - cachedBootTime = boottime + t = uint64(boottime) + atomic.StoreUint64(&cachedBootTime, t) - return boottime, nil + return t, nil } func uptime(boot uint64) uint64 { @@ -212,3 +218,7 @@ func getUsersFromUtmp(utmpfile string) ([]UserStat, error) { return ret, nil } + +func SensorsTemperatures() ([]TemperatureStat, error) { + return []TemperatureStat{}, common.ErrNotImplementedError +} diff --git a/vendor/github.com/shirou/gopsutil/host/host_linux.go b/vendor/github.com/shirou/gopsutil/host/host_linux.go index 70d8ca2ca8d..b84000cba13 100644 --- a/vendor/github.com/shirou/gopsutil/host/host_linux.go +++ b/vendor/github.com/shirou/gopsutil/host/host_linux.go @@ -9,10 +9,12 @@ import ( "io/ioutil" "os" "os/exec" + "path/filepath" "regexp" "runtime" "strconv" "strings" + "sync/atomic" "time" "github.com/shirou/gopsutil/internal/common" @@ -84,10 +86,14 @@ func Info() (*InfoStat, error) { return ret, nil } +// cachedBootTime must be accessed via atomic.Load/StoreUint64 +var cachedBootTime uint64 + // BootTime returns the system boot time expressed in seconds since the epoch. func BootTime() (uint64, error) { - if cachedBootTime != 0 { - return cachedBootTime, nil + t := atomic.LoadUint64(&cachedBootTime) + if t != 0 { + return t, nil } filename := common.HostProc("stat") lines, err := common.ReadLines(filename) @@ -104,8 +110,9 @@ func BootTime() (uint64, error) { if err != nil { return 0, err } - cachedBootTime = uint64(b) - return cachedBootTime, nil + t = uint64(b) + atomic.StoreUint64(&cachedBootTime, t) + return t, nil } } @@ -431,8 +438,8 @@ func Virtualization() (string, string, error) { system = "xen" role = "guest" // assume guest - if common.PathExists(filename + "/capabilities") { - contents, err := common.ReadLines(filename + "/capabilities") + if common.PathExists(filepath.Join(filename, "capabilities")) { + contents, err := common.ReadLines(filepath.Join(filename, "capabilities")) if err == nil { if common.StringsContains(contents, "control_d") { role = "host" @@ -454,6 +461,9 @@ func Virtualization() (string, string, error) { } else if common.StringsContains(contents, "vboxguest") { system = "vbox" role = "guest" + } else if common.StringsContains(contents, "vmware") { + system = "vmware" + role = "guest" } } } @@ -472,17 +482,17 @@ func Virtualization() (string, string, error) { } filename = common.HostProc() - if common.PathExists(filename + "/bc/0") { + if common.PathExists(filepath.Join(filename, "bc", "0")) { system = "openvz" role = "host" - } else if common.PathExists(filename + "/vz") { + } else if common.PathExists(filepath.Join(filename, "vz")) { system = "openvz" role = "guest" } // not use dmidecode because it requires root - if common.PathExists(filename + "/self/status") { - contents, err := common.ReadLines(filename + "/self/status") + if common.PathExists(filepath.Join(filename, "self", "status")) { + contents, err := common.ReadLines(filepath.Join(filename, "self", "status")) if err == nil { if common.StringsContains(contents, "s_context:") || @@ -493,8 +503,8 @@ func Virtualization() (string, string, error) { } } - if common.PathExists(filename + "/self/cgroup") { - contents, err := common.ReadLines(filename + "/self/cgroup") + if common.PathExists(filepath.Join(filename, "self", "cgroup")) { + contents, err := common.ReadLines(filepath.Join(filename, "self", "cgroup")) if err == nil { if common.StringsContains(contents, "lxc") { system = "lxc" @@ -521,3 +531,40 @@ func Virtualization() (string, string, error) { } return system, role, nil } + +func SensorsTemperatures() ([]TemperatureStat, error) { + var temperatures []TemperatureStat + files, err := filepath.Glob(common.HostSys("/class/hwmon/hwmon*/temp*_*")) + if err != nil { + return temperatures, err + } + if len(files) == 0 { + // CentOS has an intermediate /device directory: + // https://github.com/giampaolo/psutil/issues/971 + files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/temp*_*")) + if err != nil { + return temperatures, err + } + } + + for _, match := range files { + match = strings.Split(match, "_")[0] + name, err := ioutil.ReadFile(filepath.Join(filepath.Dir(match), "name")) + if err != nil { + return temperatures, err + } + current, err := ioutil.ReadFile(match + "_input") + if err != nil { + return temperatures, err + } + temperature, err := strconv.ParseFloat(string(current), 64) + if err != nil { + continue + } + temperatures = append(temperatures, TemperatureStat{ + SensorKey: string(name), + Temperature: temperature / 1000.0, + }) + } + return temperatures, nil +} diff --git a/vendor/github.com/shirou/gopsutil/host/host_openbsd.go b/vendor/github.com/shirou/gopsutil/host/host_openbsd.go index 60d46e0ec90..5565bc3a0c5 100644 --- a/vendor/github.com/shirou/gopsutil/host/host_openbsd.go +++ b/vendor/github.com/shirou/gopsutil/host/host_openbsd.go @@ -154,3 +154,7 @@ func Users() ([]UserStat, error) { return ret, nil } + +func SensorsTemperatures() ([]TemperatureStat, error) { + return []TemperatureStat{}, common.ErrNotImplementedError +} diff --git a/vendor/github.com/shirou/gopsutil/host/host_solaris.go b/vendor/github.com/shirou/gopsutil/host/host_solaris.go index ad558966e0b..41391cd8a20 100644 --- a/vendor/github.com/shirou/gopsutil/host/host_solaris.go +++ b/vendor/github.com/shirou/gopsutil/host/host_solaris.go @@ -130,3 +130,7 @@ func uptimeSince(since uint64) uint64 { func Users() ([]UserStat, error) { return []UserStat{}, common.ErrNotImplementedError } + +func SensorsTemperatures() ([]TemperatureStat, error) { + return []TemperatureStat{}, common.ErrNotImplementedError +} diff --git a/vendor/github.com/shirou/gopsutil/host/host_windows.go b/vendor/github.com/shirou/gopsutil/host/host_windows.go index 983f38cc6d5..4826f164eea 100644 --- a/vendor/github.com/shirou/gopsutil/host/host_windows.go +++ b/vendor/github.com/shirou/gopsutil/host/host_windows.go @@ -7,14 +7,14 @@ import ( "os" "runtime" "strings" - "syscall" + "sync/atomic" "time" "unsafe" "github.com/StackExchange/wmi" - "github.com/shirou/gopsutil/internal/common" process "github.com/shirou/gopsutil/process" + "golang.org/x/sys/windows" ) var ( @@ -79,12 +79,12 @@ func Info() (*InfoStat, error) { } func getMachineGuid() (string, error) { - var h syscall.Handle - err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, syscall.StringToUTF16Ptr(`SOFTWARE\Microsoft\Cryptography`), 0, syscall.KEY_READ|syscall.KEY_WOW64_64KEY, &h) + var h windows.Handle + err := windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, windows.StringToUTF16Ptr(`SOFTWARE\Microsoft\Cryptography`), 0, windows.KEY_READ|windows.KEY_WOW64_64KEY, &h) if err != nil { return "", err } - defer syscall.RegCloseKey(h) + defer windows.RegCloseKey(h) const windowsRegBufLen = 74 // len(`{`) + len(`abcdefgh-1234-456789012-123345456671` * 2) + len(`}`) // 2 == bytes/UTF16 const uuidLen = 36 @@ -92,12 +92,12 @@ func getMachineGuid() (string, error) { var regBuf [windowsRegBufLen]uint16 bufLen := uint32(windowsRegBufLen) var valType uint32 - err = syscall.RegQueryValueEx(h, syscall.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) + err = windows.RegQueryValueEx(h, windows.StringToUTF16Ptr(`MachineGuid`), nil, &valType, (*byte)(unsafe.Pointer(®Buf[0])), &bufLen) if err != nil { return "", err } - hostID := syscall.UTF16ToString(regBuf[:]) + hostID := windows.UTF16ToString(regBuf[:]) hostIDLen := len(hostID) if hostIDLen != uuidLen { return "", fmt.Errorf("HostID incorrect: %q\n", hostID) @@ -135,16 +135,21 @@ func bootTime(up uint64) uint64 { return uint64(time.Now().Unix()) - up } +// cachedBootTime must be accessed via atomic.Load/StoreUint64 +var cachedBootTime uint64 + func BootTime() (uint64, error) { - if cachedBootTime != 0 { - return cachedBootTime, nil + t := atomic.LoadUint64(&cachedBootTime) + if t != 0 { + return t, nil } up, err := Uptime() if err != nil { return 0, err } - cachedBootTime = bootTime(up) - return cachedBootTime, nil + t = bootTime(up) + atomic.StoreUint64(&cachedBootTime, t) + return t, nil } func PlatformInformation() (platform string, family string, version string, err error) { @@ -179,3 +184,7 @@ func Users() ([]UserStat, error) { return ret, nil } + +func SensorsTemperatures() ([]TemperatureStat, error) { + return []TemperatureStat{}, common.ErrNotImplementedError +} diff --git a/vendor/github.com/shirou/gopsutil/host/include/smc.c b/vendor/github.com/shirou/gopsutil/host/include/smc.c new file mode 100644 index 00000000000..30a232b7b72 --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/host/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/vendor/github.com/shirou/gopsutil/host/include/smc.h b/vendor/github.com/shirou/gopsutil/host/include/smc.h new file mode 100644 index 00000000000..b156368da31 --- /dev/null +++ b/vendor/github.com/shirou/gopsutil/host/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); diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common.go b/vendor/github.com/shirou/gopsutil/internal/common/common.go index cb6d3f3a75f..df71688b561 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common.go @@ -9,10 +9,10 @@ package common import ( "bufio" "bytes" + "context" "errors" "fmt" "io/ioutil" - "log" "net/url" "os" "os/exec" @@ -27,7 +27,7 @@ import ( var ( Timeout = 3 * time.Second - ErrTimeout = errors.New("Command timed out.") + ErrTimeout = errors.New("command timed out") ) type Invoker interface { @@ -37,8 +37,24 @@ type Invoker interface { type Invoke struct{} func (i Invoke) Command(name string, arg ...string) ([]byte, error) { - cmd := exec.Command(name, arg...) - return CombinedOutputTimeout(cmd, Timeout) + ctxt, cancel := context.WithTimeout(context.Background(), Timeout) + defer cancel() + + cmd := exec.CommandContext(ctxt, name, arg...) + + var buf bytes.Buffer + cmd.Stdout = &buf + cmd.Stderr = &buf + + if err := cmd.Start(); err != nil { + return buf.Bytes(), err + } + + if err := cmd.Wait(); err != nil { + return buf.Bytes(), err + } + + return buf.Bytes(), nil } type FakeInvoke struct { @@ -300,44 +316,6 @@ func HostEtc(combineWith ...string) string { return GetEnv("HOST_ETC", "/etc", combineWith...) } -// CombinedOutputTimeout runs the given command with the given timeout and -// returns the combined output of stdout and stderr. -// If the command times out, it attempts to kill the process. -// copied from https://github.com/influxdata/telegraf -func CombinedOutputTimeout(c *exec.Cmd, timeout time.Duration) ([]byte, error) { - var b bytes.Buffer - c.Stdout = &b - c.Stderr = &b - if err := c.Start(); err != nil { - return nil, err - } - err := WaitTimeout(c, timeout) - return b.Bytes(), err -} - -// WaitTimeout waits for the given command to finish with a timeout. -// It assumes the command has already been started. -// If the command times out, it attempts to kill the process. -// copied from https://github.com/influxdata/telegraf -func WaitTimeout(c *exec.Cmd, timeout time.Duration) error { - timer := time.NewTimer(timeout) - done := make(chan error) - go func() { done <- c.Wait() }() - select { - case err := <-done: - timer.Stop() - return err - case <-timer.C: - if err := c.Process.Kill(); err != nil { - log.Printf("FATAL error killing process: %s", err) - return err - } - // wait for the command to return after killing it - <-done - return ErrTimeout - } -} - // https://gist.github.com/kylelemons/1525278 func Pipeline(cmds ...*exec.Cmd) ([]byte, []byte, error) { // Require at least one command diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_darwin.go b/vendor/github.com/shirou/gopsutil/internal/common/common_darwin.go index 2e1552aeee3..b236da1d8cc 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_darwin.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_darwin.go @@ -6,8 +6,9 @@ import ( "os" "os/exec" "strings" - "syscall" "unsafe" + + "golang.org/x/sys/unix" ) func DoSysctrl(mib string) ([]string, error) { @@ -36,8 +37,8 @@ func CallSyscall(mib []int32) ([]byte, uint64, error) { // get required buffer size length := uint64(0) - _, _, err := syscall.Syscall6( - syscall.SYS___SYSCTL, + _, _, err := unix.Syscall6( + unix.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), uintptr(miblen), 0, @@ -54,8 +55,8 @@ func CallSyscall(mib []int32) ([]byte, uint64, error) { } // get proc info itself buf := make([]byte, length) - _, _, err = syscall.Syscall6( - syscall.SYS___SYSCTL, + _, _, err = unix.Syscall6( + unix.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), uintptr(miblen), uintptr(unsafe.Pointer(&buf[0])), diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_freebsd.go b/vendor/github.com/shirou/gopsutil/internal/common/common_freebsd.go index bda4ecfa526..668bdc40f5e 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_freebsd.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_freebsd.go @@ -6,8 +6,9 @@ import ( "os" "os/exec" "strings" - "syscall" "unsafe" + + "golang.org/x/sys/unix" ) func DoSysctrl(mib string) ([]string, error) { @@ -36,8 +37,8 @@ func CallSyscall(mib []int32) ([]byte, uint64, error) { // get required buffer size length := uint64(0) - _, _, err := syscall.Syscall6( - syscall.SYS___SYSCTL, + _, _, err := unix.Syscall6( + unix.SYS___SYSCTL, uintptr(mibptr), uintptr(miblen), 0, @@ -54,8 +55,8 @@ func CallSyscall(mib []int32) ([]byte, uint64, error) { } // get proc info itself buf := make([]byte, length) - _, _, err = syscall.Syscall6( - syscall.SYS___SYSCTL, + _, _, err = unix.Syscall6( + unix.SYS___SYSCTL, uintptr(mibptr), uintptr(miblen), uintptr(unsafe.Pointer(&buf[0])), 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 3d0fc50d668..c0aa9c78e0b 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_linux.go @@ -35,7 +35,7 @@ func NumProcs() (uint64, error) { } defer f.Close() - list, err := f.Readdir(-1) + list, err := f.Readdirnames(-1) if err != nil { return 0, err } diff --git a/vendor/github.com/shirou/gopsutil/internal/common/common_openbsd.go b/vendor/github.com/shirou/gopsutil/internal/common/common_openbsd.go index 959d9e56df9..8625e1fa927 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_openbsd.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_openbsd.go @@ -6,8 +6,9 @@ import ( "os" "os/exec" "strings" - "syscall" "unsafe" + + "golang.org/x/sys/unix" ) func DoSysctrl(mib string) ([]string, error) { @@ -36,8 +37,8 @@ func CallSyscall(mib []int32) ([]byte, uint64, error) { // get required buffer size length := uint64(0) - _, _, err := syscall.Syscall6( - syscall.SYS___SYSCTL, + _, _, err := unix.Syscall6( + unix.SYS___SYSCTL, uintptr(mibptr), uintptr(miblen), 0, @@ -54,8 +55,8 @@ func CallSyscall(mib []int32) ([]byte, uint64, error) { } // get proc info itself buf := make([]byte, length) - _, _, err = syscall.Syscall6( - syscall.SYS___SYSCTL, + _, _, err = unix.Syscall6( + unix.SYS___SYSCTL, uintptr(mibptr), uintptr(miblen), uintptr(unsafe.Pointer(&buf[0])), 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 d727378cbeb..10fc3719911 100644 --- a/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go +++ b/vendor/github.com/shirou/gopsutil/internal/common/common_windows.go @@ -3,8 +3,9 @@ package common import ( - "syscall" "unsafe" + + "golang.org/x/sys/windows" ) // for double values @@ -44,9 +45,9 @@ const ( ) var ( - Modkernel32 = syscall.NewLazyDLL("kernel32.dll") - ModNt = syscall.NewLazyDLL("ntdll.dll") - ModPdh = syscall.NewLazyDLL("pdh.dll") + Modkernel32 = windows.NewLazyDLL("kernel32.dll") + ModNt = windows.NewLazyDLL("ntdll.dll") + ModPdh = windows.NewLazyDLL("pdh.dll") ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes") ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation") @@ -77,13 +78,13 @@ func BytePtrToString(p *uint8) string { type CounterInfo struct { PostName string CounterName string - Counter syscall.Handle + Counter windows.Handle } // CreateQuery XXX // copied from https://github.com/mackerelio/mackerel-agent/ -func CreateQuery() (syscall.Handle, error) { - var query syscall.Handle +func CreateQuery() (windows.Handle, error) { + var query windows.Handle r, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query))) if r != 0 { return 0, err @@ -92,11 +93,11 @@ func CreateQuery() (syscall.Handle, error) { } // CreateCounter XXX -func CreateCounter(query syscall.Handle, pname, cname string) (*CounterInfo, error) { - var counter syscall.Handle +func CreateCounter(query windows.Handle, pname, cname string) (*CounterInfo, error) { + var counter windows.Handle r, _, err := PdhAddCounter.Call( uintptr(query), - uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(cname))), + uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(cname))), 0, uintptr(unsafe.Pointer(&counter))) if r != 0 { diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_darwin.go b/vendor/github.com/shirou/gopsutil/mem/mem_darwin.go index afd7def460e..fde000e63fb 100644 --- a/vendor/github.com/shirou/gopsutil/mem/mem_darwin.go +++ b/vendor/github.com/shirou/gopsutil/mem/mem_darwin.go @@ -6,18 +6,18 @@ import ( "encoding/binary" "strconv" "strings" - "syscall" "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/unix" ) func getHwMemsize() (uint64, error) { - totalString, err := syscall.Sysctl("hw.memsize") + totalString, err := unix.Sysctl("hw.memsize") if err != nil { return 0, err } - // syscall.sysctl() helpfully assumes the result is a null-terminated string and + // unix.sysctl() helpfully assumes the result is a null-terminated string and // removes the last byte of the result if it's 0 :/ totalString += "\x00" diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_darwin_cgo.go b/vendor/github.com/shirou/gopsutil/mem/mem_darwin_cgo.go index 461631976e8..4b5a6b9e31b 100644 --- a/vendor/github.com/shirou/gopsutil/mem/mem_darwin_cgo.go +++ b/vendor/github.com/shirou/gopsutil/mem/mem_darwin_cgo.go @@ -10,8 +10,9 @@ import "C" import ( "fmt" - "syscall" "unsafe" + + "golang.org/x/sys/unix" ) // VirtualMemory returns VirtualmemoryStat. @@ -28,7 +29,7 @@ func VirtualMemory() (*VirtualMemoryStat, error) { return nil, fmt.Errorf("host_statistics error=%d", status) } - pageSize := uint64(syscall.Getpagesize()) + pageSize := uint64(unix.Getpagesize()) total, err := getHwMemsize() if err != nil { return nil, err diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_darwin_nocgo.go b/vendor/github.com/shirou/gopsutil/mem/mem_darwin_nocgo.go index 3eb33abb1bc..79af790d0b6 100644 --- a/vendor/github.com/shirou/gopsutil/mem/mem_darwin_nocgo.go +++ b/vendor/github.com/shirou/gopsutil/mem/mem_darwin_nocgo.go @@ -7,7 +7,8 @@ import ( "os/exec" "strconv" "strings" - "syscall" + + "golang.org/x/sys/unix" ) // Runs vm_stat and returns Free and inactive pages @@ -27,7 +28,7 @@ func parseVMStat(out string, vms *VirtualMemoryStat) error { var err error lines := strings.Split(out, "\n") - pagesize := uint64(syscall.Getpagesize()) + pagesize := uint64(unix.Getpagesize()) for _, line := range lines { fields := strings.Split(line, ":") if len(fields) < 2 { diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_linux.go b/vendor/github.com/shirou/gopsutil/mem/mem_linux.go index e7540af74a6..fda3345ba74 100644 --- a/vendor/github.com/shirou/gopsutil/mem/mem_linux.go +++ b/vendor/github.com/shirou/gopsutil/mem/mem_linux.go @@ -5,9 +5,9 @@ package mem import ( "strconv" "strings" - "syscall" "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/unix" ) func VirtualMemory() (*VirtualMemoryStat, error) { @@ -72,9 +72,9 @@ func VirtualMemory() (*VirtualMemoryStat, error) { } func SwapMemory() (*SwapMemoryStat, error) { - sysinfo := &syscall.Sysinfo_t{} + sysinfo := &unix.Sysinfo_t{} - if err := syscall.Sysinfo(sysinfo); err != nil { + if err := unix.Sysinfo(sysinfo); err != nil { return nil, err } ret := &SwapMemoryStat{ diff --git a/vendor/github.com/shirou/gopsutil/mem/mem_windows.go b/vendor/github.com/shirou/gopsutil/mem/mem_windows.go index 045af49e39d..b56f25ec2bb 100644 --- a/vendor/github.com/shirou/gopsutil/mem/mem_windows.go +++ b/vendor/github.com/shirou/gopsutil/mem/mem_windows.go @@ -3,10 +3,10 @@ package mem import ( - "syscall" "unsafe" "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/windows" ) var ( @@ -30,7 +30,7 @@ func VirtualMemory() (*VirtualMemoryStat, error) { memInfo.cbSize = uint32(unsafe.Sizeof(memInfo)) mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo))) if mem == 0 { - return nil, syscall.GetLastError() + return nil, windows.GetLastError() } ret := &VirtualMemoryStat{ diff --git a/vendor/github.com/shirou/gopsutil/net/net_darwin.go b/vendor/github.com/shirou/gopsutil/net/net_darwin.go index f1065c6d01f..c60a00457b6 100644 --- a/vendor/github.com/shirou/gopsutil/net/net_darwin.go +++ b/vendor/github.com/shirou/gopsutil/net/net_darwin.go @@ -18,7 +18,7 @@ var ( const endOfLine = "\n" -func parseNetstatLine(line string) (stat *IOCountersStat, linkId *uint, err error) { +func parseNetstatLine(line string) (stat *IOCountersStat, linkID *uint, err error) { var ( numericValue uint64 columns = strings.Fields(line) @@ -35,8 +35,8 @@ func parseNetstatLine(line string) (stat *IOCountersStat, linkId *uint, err erro if err != nil { return } - linkIdUint := uint(numericValue) - linkId = &linkIdUint + linkIDUint := uint(numericValue) + linkID = &linkIDUint } base := 1 @@ -91,7 +91,7 @@ func parseNetstatLine(line string) (stat *IOCountersStat, linkId *uint, err erro } type netstatInterface struct { - linkId *uint + linkID *uint stat *IOCountersStat } @@ -112,7 +112,7 @@ func parseNetstatOutput(output string) ([]netstatInterface, error) { for index := 0; index < numberInterfaces; index++ { nsIface := netstatInterface{} - if nsIface.stat, nsIface.linkId, err = parseNetstatLine(lines[index+1]); err != nil { + if nsIface.stat, nsIface.linkID, err = parseNetstatLine(lines[index+1]); err != nil { return nil, err } interfaces[index] = nsIface @@ -126,7 +126,7 @@ type mapInterfaceNameUsage map[string]uint func newMapInterfaceNameUsage(ifaces []netstatInterface) mapInterfaceNameUsage { output := make(mapInterfaceNameUsage) for index := range ifaces { - if ifaces[index].linkId != nil { + if ifaces[index].linkID != nil { ifaceName := ifaces[index].stat.Name usage, ok := output[ifaceName] if ok { @@ -192,7 +192,7 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) { if !ifaceUsage.isTruncated() { // no truncated interface name, return stats of all interface with for index := range nsInterfaces { - if nsInterfaces[index].linkId != nil { + if nsInterfaces[index].linkID != nil { ret[retIndex] = *nsInterfaces[index].stat retIndex++ } @@ -212,7 +212,7 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) { for _, interfaceName := range interfaceNames { truncated := true for index := range nsInterfaces { - if nsInterfaces[index].linkId != nil && nsInterfaces[index].stat.Name == interfaceName { + if nsInterfaces[index].linkID != nil && nsInterfaces[index].stat.Name == interfaceName { // handle the non truncated name to avoid execute netstat for them again ret[retIndex] = *nsInterfaces[index].stat retIndex++ @@ -234,7 +234,7 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) { continue } for index := range parsedIfaces { - if parsedIfaces[index].linkId != nil { + if parsedIfaces[index].linkID != nil { ret = append(ret, *parsedIfaces[index].stat) break } diff --git a/vendor/github.com/shirou/gopsutil/net/net_linux.go b/vendor/github.com/shirou/gopsutil/net/net_linux.go index 58c07290ca6..9ed4533696f 100644 --- a/vendor/github.com/shirou/gopsutil/net/net_linux.go +++ b/vendor/github.com/shirou/gopsutil/net/net_linux.go @@ -3,6 +3,7 @@ package net import ( + "bytes" "encoding/hex" "errors" "fmt" @@ -32,15 +33,20 @@ func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) { return nil, err } + parts := make([]string, 2) + statlen := len(lines) - 1 ret := make([]IOCountersStat, 0, statlen) for _, line := range lines[2:] { - parts := strings.SplitN(line, ": ", 2) - if len(parts) != 2 { + separatorPos := strings.LastIndex(line, ":") + if separatorPos == -1 { continue } + parts[0] = line[0:separatorPos] + parts[1] = line[separatorPos+1:] + interfaceName := strings.TrimSpace(parts[0]) if interfaceName == "" { continue @@ -256,17 +262,17 @@ var kindUNIX = netConnectionKindType{ } var netConnectionKindMap = map[string][]netConnectionKindType{ - "all": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX}, - "tcp": []netConnectionKindType{kindTCP4, kindTCP6}, - "tcp4": []netConnectionKindType{kindTCP4}, - "tcp6": []netConnectionKindType{kindTCP6}, - "udp": []netConnectionKindType{kindUDP4, kindUDP6}, - "udp4": []netConnectionKindType{kindUDP4}, - "udp6": []netConnectionKindType{kindUDP6}, - "unix": []netConnectionKindType{kindUNIX}, - "inet": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6}, - "inet4": []netConnectionKindType{kindTCP4, kindUDP4}, - "inet6": []netConnectionKindType{kindTCP6, kindUDP6}, + "all": {kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX}, + "tcp": {kindTCP4, kindTCP6}, + "tcp4": {kindTCP4}, + "tcp6": {kindTCP6}, + "udp": {kindUDP4, kindUDP6}, + "udp4": {kindUDP4}, + "udp6": {kindUDP6}, + "unix": {kindUNIX}, + "inet": {kindTCP4, kindTCP6, kindUDP4, kindUDP6}, + "inet4": {kindTCP4, kindUDP4}, + "inet6": {kindTCP6, kindUDP6}, } type inodeMap struct { @@ -346,12 +352,13 @@ func ConnectionsPidMax(kind string, pid int32, max int) ([]ConnectionStat, error } func statsFromInodes(root string, pid int32, tmap []netConnectionKindType, inodes map[string][]inodeMap) ([]ConnectionStat, error) { - dupCheckMap := make(map[connTmp]struct{}) + dupCheckMap := make(map[string]struct{}) var ret []ConnectionStat var err error for _, t := range tmap { var path string + var connKey string var ls []connTmp path = fmt.Sprintf("%s/net/%s", root, t.filename) switch t.family { @@ -366,7 +373,11 @@ func statsFromInodes(root string, pid int32, tmap []netConnectionKindType, inode return nil, err } for _, c := range ls { - if _, ok := dupCheckMap[c]; ok { + // Build TCP key to id the connection uniquely + // socket type, src ip, src port, dst ip, dst port and state should be enough + // to prevent duplications. + connKey = fmt.Sprintf("%d-%s:%d-%s:%d-%s", c.sockType, c.laddr.IP, c.laddr.Port, c.raddr.IP, c.raddr.Port, c.status) + if _, ok := dupCheckMap[connKey]; ok { continue } @@ -390,7 +401,7 @@ func statsFromInodes(root string, pid int32, tmap []netConnectionKindType, inode conn.Uids, _ = proc.getUids() ret = append(ret, conn) - dupCheckMap[c] = struct{}{} + dupCheckMap[connKey] = struct{}{} } } @@ -405,12 +416,12 @@ func getProcInodes(root string, pid int32, max int) (map[string][]inodeMap, erro dir := fmt.Sprintf("%s/%d/fd", root, pid) f, err := os.Open(dir) if err != nil { - return ret, nil + return ret, err } defer f.Close() files, err := f.Readdir(max) if err != nil { - return ret, nil + return ret, err } for _, fd := range files { inodePath := fmt.Sprintf("%s/%d/fd/%s", root, pid, fd.Name()) @@ -603,14 +614,22 @@ func processInet(file string, kind netConnectionKindType, inodes map[string][]in // IPv6 not supported, return empty. return []connTmp{}, nil } - lines, err := common.ReadLines(file) + + // Read the contents of the /proc file with a single read sys call. + // This minimizes duplicates in the returned connections + // For more info: + // https://github.com/shirou/gopsutil/pull/361 + contents, err := ioutil.ReadFile(file) if err != nil { return nil, err } + + lines := bytes.Split(contents, []byte("\n")) + var ret []connTmp // skip first line for _, line := range lines[1:] { - l := strings.Fields(line) + l := strings.Fields(string(line)) if len(l) < 10 { continue } @@ -657,15 +676,21 @@ func processInet(file string, kind netConnectionKindType, inodes map[string][]in } func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) { - lines, err := common.ReadLines(file) + // Read the contents of the /proc file with a single read sys call. + // This minimizes duplicates in the returned connections + // For more info: + // https://github.com/shirou/gopsutil/pull/361 + contents, err := ioutil.ReadFile(file) if err != nil { return nil, err } + lines := bytes.Split(contents, []byte("\n")) + var ret []connTmp // skip first line for _, line := range lines[1:] { - tokens := strings.Fields(line) + tokens := strings.Fields(string(line)) if len(tokens) < 6 { continue } @@ -680,7 +705,7 @@ func processUnix(file string, kind netConnectionKindType, inodes map[string][]in pairs, exists := inodes[inode] if !exists { pairs = []inodeMap{ - inodeMap{}, + {}, } } for _, pair := range pairs { diff --git a/vendor/github.com/shirou/gopsutil/net/net_windows.go b/vendor/github.com/shirou/gopsutil/net/net_windows.go index 996e83226ac..e26a130797b 100644 --- a/vendor/github.com/shirou/gopsutil/net/net_windows.go +++ b/vendor/github.com/shirou/gopsutil/net/net_windows.go @@ -6,13 +6,13 @@ import ( "errors" "net" "os" - "syscall" "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/windows" ) var ( - modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") + modiphlpapi = windows.NewLazyDLL("iphlpapi.dll") procGetExtendedTCPTable = modiphlpapi.NewProc("GetExtendedTcpTable") procGetExtendedUDPTable = modiphlpapi.NewProc("GetExtendedUdpTable") ) @@ -41,8 +41,8 @@ func IOCounters(pernic bool) ([]IOCountersStat, error) { Name: ifi.Name, } - row := syscall.MibIfRow{Index: uint32(ifi.Index)} - e := syscall.GetIfEntry(&row) + row := windows.MibIfRow{Index: uint32(ifi.Index)} + e := windows.GetIfEntry(&row) if e != nil { return nil, os.NewSyscallError("GetIfEntry", e) } diff --git a/vendor/github.com/shirou/gopsutil/process/process.go b/vendor/github.com/shirou/gopsutil/process/process.go index b97f777fdff..f740e42c988 100644 --- a/vendor/github.com/shirou/gopsutil/process/process.go +++ b/vendor/github.com/shirou/gopsutil/process/process.go @@ -186,3 +186,20 @@ func (p *Process) MemoryPercent() (float32, error) { return (100 * float32(used) / float32(total)), nil } +// CPU_Percent returns how many percent of the CPU time this process uses +func (p *Process) CPUPercent() (float64, error) { + crt_time, err := p.CreateTime() + if err != nil { + return 0, err + } + + + cpu, err := p.Times() + if err != nil { + return 0, err + } + + + return (100 * (cpu.Total()) / float64(time.Now().Unix()-(crt_time/1000))), nil +} + diff --git a/vendor/github.com/shirou/gopsutil/process/process_darwin.go b/vendor/github.com/shirou/gopsutil/process/process_darwin.go index 883c88bb779..63b64f6ca24 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_darwin.go +++ b/vendor/github.com/shirou/gopsutil/process/process_darwin.go @@ -9,13 +9,13 @@ import ( "os/exec" "strconv" "strings" - "syscall" "time" "unsafe" "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/internal/common" "github.com/shirou/gopsutil/net" + "golang.org/x/sys/unix" ) // copied from sys/sysctl.h @@ -99,8 +99,8 @@ func (p *Process) Exe() (string, error) { return "", err } - lsof := exec.Command(lsof_bin, "-p", strconv.Itoa(int(p.Pid)), "-Fn") - awk := exec.Command(awk_bin, "NR==3{print}") + lsof := exec.Command(lsof_bin, "-p", strconv.Itoa(int(p.Pid)), "-Fpfn") + awk := exec.Command(awk_bin, "NR==5{print}") sed := exec.Command(sed_bin, "s/n\\//\\//") output, _, err := common.Pipeline(lsof, awk, sed) @@ -152,7 +152,7 @@ func (p *Process) CreateTime() (int64, error) { elapsedDurations = append(elapsedDurations, time.Duration(p)) } - var elapsed time.Duration = time.Duration(elapsedDurations[0]) * time.Second + var elapsed = time.Duration(elapsedDurations[0]) * time.Second if len(elapsedDurations) > 1 { elapsed += time.Duration(elapsedDurations[1]) * time.Minute } @@ -443,8 +443,8 @@ func (p *Process) getKProc() (*KinfoProc, error) { procK := KinfoProc{} length := uint64(unsafe.Sizeof(procK)) buf := make([]byte, length) - _, _, syserr := syscall.Syscall6( - syscall.SYS___SYSCTL, + _, _, syserr := unix.Syscall6( + unix.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), uintptr(len(mib)), uintptr(unsafe.Pointer(&buf[0])), diff --git a/vendor/github.com/shirou/gopsutil/process/process_freebsd.go b/vendor/github.com/shirou/gopsutil/process/process_freebsd.go index 5362128e6e5..47c14f4c842 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_freebsd.go +++ b/vendor/github.com/shirou/gopsutil/process/process_freebsd.go @@ -6,11 +6,11 @@ import ( "bytes" "encoding/binary" "strings" - "syscall" cpu "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/internal/common" net "github.com/shirou/gopsutil/net" + "golang.org/x/sys/unix" ) // MemoryInfoExStat is different between OSes @@ -223,7 +223,7 @@ func (p *Process) MemoryInfo() (*MemoryInfoStat, error) { if err != nil { return nil, err } - v, err := syscall.Sysctl("vm.stats.vm.v_page_size") + v, err := unix.Sysctl("vm.stats.vm.v_page_size") if err != nil { return nil, err } diff --git a/vendor/github.com/shirou/gopsutil/process/process_linux.go b/vendor/github.com/shirou/gopsutil/process/process_linux.go index 5b5c6bcc1e0..c0d81c28a61 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_linux.go +++ b/vendor/github.com/shirou/gopsutil/process/process_linux.go @@ -14,12 +14,12 @@ import ( "path/filepath" "strconv" "strings" - "syscall" "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/host" "github.com/shirou/gopsutil/internal/common" "github.com/shirou/gopsutil/net" + "golang.org/x/sys/unix" ) var ( @@ -117,7 +117,7 @@ func (p *Process) CmdlineSlice() ([]string, error) { return p.fillSliceFromCmdline() } -// CreateTime returns created time of the process in seconds since the epoch, in UTC. +// CreateTime returns created time of the process in milliseconds since the epoch, in UTC. func (p *Process) CreateTime() (int64, error) { _, _, _, createTime, _, err := p.fillFromStat() if err != nil { @@ -857,7 +857,7 @@ func (p *Process) fillFromStat() (string, int32, *cpu.TimesStat, int64, int32, e // p.Nice = mustParseInt32(fields[18]) // use syscall instead of parse Stat file - snice, _ := syscall.Getpriority(PrioProcess, int(pid)) + snice, _ := unix.Getpriority(PrioProcess, int(pid)) nice := int32(snice) // FIXME: is this true? return terminal, int32(ppid), cpuTimes, createTime, nice, nil diff --git a/vendor/github.com/shirou/gopsutil/process/process_openbsd.go b/vendor/github.com/shirou/gopsutil/process/process_openbsd.go index b51826ce1a9..47a6e377c22 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_openbsd.go +++ b/vendor/github.com/shirou/gopsutil/process/process_openbsd.go @@ -7,13 +7,13 @@ import ( "bytes" "encoding/binary" "strings" - "syscall" "unsafe" cpu "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/internal/common" mem "github.com/shirou/gopsutil/mem" net "github.com/shirou/gopsutil/net" + "golang.org/x/sys/unix" ) // MemoryInfoExStat is different between OSes @@ -328,8 +328,8 @@ func CallKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) { mibptr := unsafe.Pointer(&mib[0]) miblen := uint64(len(mib)) length := uint64(0) - _, _, err := syscall.Syscall6( - syscall.SYS___SYSCTL, + _, _, err := unix.Syscall6( + unix.SYS___SYSCTL, uintptr(mibptr), uintptr(miblen), 0, @@ -346,8 +346,8 @@ func CallKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) { miblen = uint64(len(mib)) // get proc info itself buf := make([]byte, length) - _, _, err = syscall.Syscall6( - syscall.SYS___SYSCTL, + _, _, err = unix.Syscall6( + unix.SYS___SYSCTL, uintptr(mibptr), uintptr(miblen), uintptr(unsafe.Pointer(&buf[0])), diff --git a/vendor/github.com/shirou/gopsutil/process/process_posix.go b/vendor/github.com/shirou/gopsutil/process/process_posix.go index b22a72d8aa2..55c9c009c07 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_posix.go +++ b/vendor/github.com/shirou/gopsutil/process/process_posix.go @@ -4,14 +4,13 @@ package process import ( "os" - "os/exec" "os/user" "path/filepath" "strconv" "strings" "syscall" - "github.com/shirou/gopsutil/internal/common" + "golang.org/x/sys/unix" ) // POSIX @@ -53,8 +52,8 @@ func getTerminalMap() (map[uint64]string, error) { } for _, name := range termfiles { - stat := syscall.Stat_t{} - if err = syscall.Stat(name, &stat); err != nil { + stat := unix.Stat_t{} + if err = unix.Stat(name, &stat); err != nil { return nil, err } rdev := uint64(stat.Rdev) @@ -63,31 +62,15 @@ func getTerminalMap() (map[uint64]string, error) { return ret, nil } -// SendSignal sends a syscall.Signal to the process. +// SendSignal sends a unix.Signal to the process. // Currently, SIGSTOP, SIGCONT, SIGTERM and SIGKILL are supported. func (p *Process) SendSignal(sig syscall.Signal) error { - sigAsStr := "INT" - switch sig { - case syscall.SIGSTOP: - sigAsStr = "STOP" - case syscall.SIGCONT: - sigAsStr = "CONT" - case syscall.SIGTERM: - sigAsStr = "TERM" - case syscall.SIGKILL: - sigAsStr = "KILL" - } - - kill, err := exec.LookPath("kill") + process, err := os.FindProcess(int(p.Pid)) if err != nil { return err } - cmd := exec.Command(kill, "-s", sigAsStr, strconv.Itoa(int(p.Pid))) - cmd.Stderr = os.Stderr - if err := cmd.Start(); err != nil { - return err - } - err = common.WaitTimeout(cmd, common.Timeout) + + err = process.Signal(sig) if err != nil { return err } @@ -97,22 +80,22 @@ func (p *Process) SendSignal(sig syscall.Signal) error { // Suspend sends SIGSTOP to the process. func (p *Process) Suspend() error { - return p.SendSignal(syscall.SIGSTOP) + return p.SendSignal(unix.SIGSTOP) } // Resume sends SIGCONT to the process. func (p *Process) Resume() error { - return p.SendSignal(syscall.SIGCONT) + return p.SendSignal(unix.SIGCONT) } // Terminate sends SIGTERM to the process. func (p *Process) Terminate() error { - return p.SendSignal(syscall.SIGTERM) + return p.SendSignal(unix.SIGTERM) } // Kill sends SIGKILL to the process. func (p *Process) Kill() error { - return p.SendSignal(syscall.SIGKILL) + return p.SendSignal(unix.SIGKILL) } // Username returns a username of the process. diff --git a/vendor/github.com/shirou/gopsutil/process/process_windows.go b/vendor/github.com/shirou/gopsutil/process/process_windows.go index 7507ab036f7..b13a5af9e57 100644 --- a/vendor/github.com/shirou/gopsutil/process/process_windows.go +++ b/vendor/github.com/shirou/gopsutil/process/process_windows.go @@ -3,7 +3,6 @@ package process import ( - "errors" "fmt" "strings" "syscall" @@ -11,11 +10,11 @@ import ( "unsafe" "github.com/StackExchange/wmi" - "github.com/shirou/w32" - cpu "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/internal/common" net "github.com/shirou/gopsutil/net" + "github.com/shirou/w32" + "golang.org/x/sys/windows" ) const ( @@ -24,7 +23,7 @@ const ( ) var ( - modpsapi = syscall.NewLazyDLL("psapi.dll") + modpsapi = windows.NewLazyDLL("psapi.dll") procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") ) @@ -51,45 +50,46 @@ type MemoryMapsStat struct { } 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 - */ + 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 +} + +func init() { + wmi.DefaultClient.AllowMissingFields = true } func Pids() ([]int32, error) { @@ -108,24 +108,27 @@ func Pids() ([]int32, error) { } func (p *Process) Ppid() (int32, error) { - ret, _, _, err := p.getFromSnapProcess(p.Pid) + dst, err := GetWin32Proc(p.Pid) if err != nil { return 0, err } - return ret, nil + + return int32(dst[0].ParentProcessID), nil } func GetWin32Proc(pid int32) ([]Win32_Process, error) { var dst []Win32_Process query := fmt.Sprintf("WHERE ProcessId = %d", pid) q := wmi.CreateQuery(&dst, query) - err := wmi.Query(q, &dst) - if err != nil { + + if err := wmi.Query(q, &dst); err != nil { return []Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err) } - if len(dst) != 1 { + + if len(dst) == 0 { return []Win32_Process{}, fmt.Errorf("could not get win32Proc: empty") } + return dst, nil } @@ -136,6 +139,7 @@ func (p *Process) Name() (string, error) { } return dst[0].Name, nil } + func (p *Process) Exe() (string, error) { dst, err := GetWin32Proc(p.Pid) if err != nil { @@ -143,6 +147,7 @@ func (p *Process) Exe() (string, error) { } return *dst[0].ExecutablePath, nil } + func (p *Process) Cmdline() (string, error) { dst, err := GetWin32Proc(p.Pid) if err != nil { @@ -175,14 +180,37 @@ func (p *Process) Cwd() (string, error) { return "", common.ErrNotImplementedError } func (p *Process) Parent() (*Process, error) { - return p, common.ErrNotImplementedError + dst, err := GetWin32Proc(p.Pid) + if err != nil { + return nil, fmt.Errorf("could not get ParentProcessID: %s", err) + } + + return NewProcess(int32(dst[0].ParentProcessID)) } func (p *Process) Status() (string, error) { return "", common.ErrNotImplementedError } func (p *Process) Username() (string, error) { - return "", common.ErrNotImplementedError + pid := p.Pid + // 0x1000 is PROCESS_QUERY_LIMITED_INFORMATION + c, err := syscall.OpenProcess(0x1000, false, uint32(pid)) + if err != nil { + return "", err + } + defer syscall.CloseHandle(c) + + var token syscall.Token + err = syscall.OpenProcessToken(c, syscall.TOKEN_QUERY, &token) + if err != nil { + return "", err + } + defer token.Close() + tokenUser, err := token.GetTokenUser() + + user, domain, _, err := tokenUser.User.Sid.LookupAccount("") + return domain + "\\" + user, err } + func (p *Process) Uids() ([]int32, error) { var uids []int32 @@ -268,7 +296,23 @@ func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { } func (p *Process) Children() ([]*Process, error) { - return nil, common.ErrNotImplementedError + procs, err := processes() + if err != nil { + return nil, err + } + out := []*Process{} + + for _, proc := range procs { + parent, err := proc.Parent() + if err != nil { + continue + } + + if parent.Pid == p.Pid { + out = append(out, proc) + } + } + return out, nil } func (p *Process) OpenFiles() ([]OpenFilesStat, error) { @@ -298,7 +342,7 @@ func NewProcess(pid int32) (*Process, error) { return p, nil } -func (p *Process) SendSignal(sig syscall.Signal) error { +func (p *Process) SendSignal(sig windows.Signal) error { return common.ErrNotImplementedError } @@ -316,7 +360,7 @@ func (p *Process) Terminate() error { w32.CloseHandle(proc) if ret == false { - return syscall.GetLastError() + return windows.GetLastError() } else { return nil } @@ -329,32 +373,31 @@ func (p *Process) Kill() error { func (p *Process) getFromSnapProcess(pid int32) (int32, int32, string, error) { snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPPROCESS, uint32(pid)) if snap == 0 { - return 0, 0, "", syscall.GetLastError() + return 0, 0, "", windows.GetLastError() } defer w32.CloseHandle(snap) var pe32 w32.PROCESSENTRY32 pe32.DwSize = uint32(unsafe.Sizeof(pe32)) if w32.Process32First(snap, &pe32) == false { - return 0, 0, "", syscall.GetLastError() + return 0, 0, "", windows.GetLastError() } if pe32.Th32ProcessID == uint32(pid) { - szexe := syscall.UTF16ToString(pe32.SzExeFile[:]) + szexe := windows.UTF16ToString(pe32.SzExeFile[:]) return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil } for w32.Process32Next(snap, &pe32) { if pe32.Th32ProcessID == uint32(pid) { - szexe := syscall.UTF16ToString(pe32.SzExeFile[:]) + szexe := windows.UTF16ToString(pe32.SzExeFile[:]) return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil } } - return 0, 0, "", errors.New("Couldn't find pid:" + string(pid)) + return 0, 0, "", fmt.Errorf("Couldn't find pid: %d", pid) } // Get processes func processes() ([]*Process, error) { - var dst []Win32_Process q := wmi.CreateQuery(&dst, "") err := wmi.Query(q, &dst) @@ -364,7 +407,8 @@ func processes() ([]*Process, error) { if len(dst) == 0 { return []*Process{}, fmt.Errorf("could not get Process") } - results := make([]*Process, 0, len(dst)) + + results := []*Process{} for _, proc := range dst { p, err := NewProcess(int32(proc.ProcessID)) if err != nil { @@ -388,22 +432,22 @@ func getProcInfo(pid int32) (*SystemProcessInformation, error) { uintptr(unsafe.Pointer(&bufferSize)), uintptr(unsafe.Pointer(&bufferSize))) if ret != 0 { - return nil, syscall.GetLastError() + return nil, windows.GetLastError() } return &sysProcInfo, nil } -func getRusage(pid int32) (*syscall.Rusage, error) { - var CPU syscall.Rusage +func getRusage(pid int32) (*windows.Rusage, error) { + var CPU windows.Rusage - c, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid)) + c, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, uint32(pid)) if err != nil { return nil, err } - defer syscall.CloseHandle(c) + defer windows.CloseHandle(c) - if err := syscall.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil { + if err := windows.GetProcessTimes(c, &CPU.CreationTime, &CPU.ExitTime, &CPU.KernelTime, &CPU.UserTime); err != nil { return nil, err } @@ -412,11 +456,12 @@ func getRusage(pid int32) (*syscall.Rusage, error) { func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) { var mem PROCESS_MEMORY_COUNTERS - c, err := syscall.OpenProcess(syscall.PROCESS_QUERY_INFORMATION, false, uint32(pid)) + // PROCESS_QUERY_LIMITED_INFORMATION is 0x1000 + c, err := windows.OpenProcess(0x1000, false, uint32(pid)) if err != nil { return mem, err } - defer syscall.CloseHandle(c) + defer windows.CloseHandle(c) if err := getProcessMemoryInfo(c, &mem); err != nil { return mem, err } @@ -424,7 +469,7 @@ func getMemoryInfo(pid int32) (PROCESS_MEMORY_COUNTERS, error) { return mem, err } -func getProcessMemoryInfo(h syscall.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) { +func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err error) { r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(h), uintptr(unsafe.Pointer(mem)), uintptr(unsafe.Sizeof(*mem))) if r1 == 0 { if e1 != 0 { diff --git a/vendor/github.com/ugorji/go/codec/binc.go b/vendor/github.com/ugorji/go/codec/binc.go index 681b2b0daea..618c51505f6 100644 --- a/vendor/github.com/ugorji/go/codec/binc.go +++ b/vendor/github.com/ugorji/go/codec/binc.go @@ -356,6 +356,9 @@ func (d *bincDecDriver) uncacheRead() { } func (d *bincDecDriver) ContainerType() (vt valueType) { + if !d.bdRead { + d.readNextBd() + } if d.vd == bincVdSpecial && d.vs == bincSpNil { return valueTypeNil } else if d.vd == bincVdByteArray { @@ -580,6 +583,9 @@ func (d *bincDecDriver) DecodeBool() (b bool) { } func (d *bincDecDriver) ReadMapStart() (length int) { + if !d.bdRead { + d.readNextBd() + } if d.vd != bincVdMap { d.d.errorf("Invalid d.vd for map. Expecting 0x%x. Got: 0x%x", bincVdMap, d.vd) return @@ -590,6 +596,9 @@ func (d *bincDecDriver) ReadMapStart() (length int) { } func (d *bincDecDriver) ReadArrayStart() (length int) { + if !d.bdRead { + d.readNextBd() + } if d.vd != bincVdArray { d.d.errorf("Invalid d.vd for array. Expecting 0x%x. Got: 0x%x", bincVdArray, d.vd) return @@ -910,7 +919,7 @@ func (h *BincHandle) newEncDriver(e *Encoder) encDriver { } func (h *BincHandle) newDecDriver(d *Decoder) decDriver { - return &bincDecDriver{d: d, r: d.r, h: h, br: d.bytes} + return &bincDecDriver{d: d, h: h, r: d.r, br: d.bytes} } func (e *bincEncDriver) reset() { @@ -920,7 +929,7 @@ func (e *bincEncDriver) reset() { } func (d *bincDecDriver) reset() { - d.r = d.d.r + d.r, d.br = d.d.r, d.d.bytes d.s = nil d.bd, d.bdRead, d.vd, d.vs = 0, false, 0, 0 } diff --git a/vendor/github.com/ugorji/go/codec/cbor.go b/vendor/github.com/ugorji/go/codec/cbor.go index c87e3f4d4dc..4c72caffb21 100644 --- a/vendor/github.com/ugorji/go/codec/cbor.go +++ b/vendor/github.com/ugorji/go/codec/cbor.go @@ -196,6 +196,9 @@ func (d *cborDecDriver) uncacheRead() { } func (d *cborDecDriver) ContainerType() (vt valueType) { + if !d.bdRead { + d.readNextBd() + } if d.bd == cborBdNil { return valueTypeNil } else if d.bd == cborBdIndefiniteBytes || (d.bd >= cborBaseBytes && d.bd < cborBaseString) { @@ -351,6 +354,9 @@ func (d *cborDecDriver) DecodeBool() (b bool) { } func (d *cborDecDriver) ReadMapStart() (length int) { + if !d.bdRead { + d.readNextBd() + } d.bdRead = false if d.bd == cborBdIndefiniteMap { return -1 @@ -359,6 +365,9 @@ func (d *cborDecDriver) ReadMapStart() (length int) { } func (d *cborDecDriver) ReadArrayStart() (length int) { + if !d.bdRead { + d.readNextBd() + } d.bdRead = false if d.bd == cborBdIndefiniteArray { return -1 @@ -576,7 +585,7 @@ func (h *CborHandle) newEncDriver(e *Encoder) encDriver { } func (h *CborHandle) newDecDriver(d *Decoder) decDriver { - return &cborDecDriver{d: d, r: d.r, h: h, br: d.bytes} + return &cborDecDriver{d: d, h: h, r: d.r, br: d.bytes} } func (e *cborEncDriver) reset() { @@ -584,7 +593,7 @@ func (e *cborEncDriver) reset() { } func (d *cborDecDriver) reset() { - d.r = d.d.r + d.r, d.br = d.d.r, d.d.bytes d.bd, d.bdRead = 0, false } diff --git a/vendor/github.com/ugorji/go/codec/codecgen/gen.go b/vendor/github.com/ugorji/go/codec/codecgen/gen.go index d5e214c37f7..346d780ee72 100644 --- a/vendor/github.com/ugorji/go/codec/codecgen/gen.go +++ b/vendor/github.com/ugorji/go/codec/codecgen/gen.go @@ -20,6 +20,7 @@ import ( "path/filepath" "regexp" "strconv" + "strings" "text/template" "time" ) @@ -135,6 +136,9 @@ func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, if tv.ImportPath == tv.CodecImportPath { tv.CodecPkgFiles = true tv.CodecPkgName = "codec" + } else { + // HACK: always handle vendoring. It should be typically on in go 1.6, 1.7 + tv.ImportPath = stripVendor(tv.ImportPath) } astfiles := make([]*ast.File, len(infiles)) for i, infile := range infiles { @@ -160,6 +164,31 @@ func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, } } + // keep track of types with selfer methods + // selferMethods := []string{"CodecEncodeSelf", "CodecDecodeSelf"} + selferEncTyps := make(map[string]bool) + selferDecTyps := make(map[string]bool) + for _, f := range astfiles { + for _, d := range f.Decls { + // if fd, ok := d.(*ast.FuncDecl); ok && fd.Recv != nil && fd.Recv.NumFields() == 1 { + if fd, ok := d.(*ast.FuncDecl); ok && fd.Recv != nil && len(fd.Recv.List) == 1 { + recvType := fd.Recv.List[0].Type + if ptr, ok := recvType.(*ast.StarExpr); ok { + recvType = ptr.X + } + if id, ok := recvType.(*ast.Ident); ok { + switch fd.Name.Name { + case "CodecEncodeSelf": + selferEncTyps[id.Name] = true + case "CodecDecodeSelf": + selferDecTyps[id.Name] = true + } + } + } + } + } + + // now find types for _, f := range astfiles { for _, d := range f.Decls { if gd, ok := d.(*ast.GenDecl); ok { @@ -180,7 +209,14 @@ func Generate(outfile, buildTag, codecPkgPath string, uid int64, useUnsafe bool, // FuncType, InterfaceType, StarExpr (ptr), etc switch td.Type.(type) { case *ast.StructType, *ast.Ident, *ast.MapType, *ast.ArrayType, *ast.ChanType: - if regexName.FindStringIndex(td.Name.Name) != nil && notRegexName.FindStringIndex(td.Name.Name) == nil { + // only add to tv.Types iff + // - it matches per the -r parameter + // - it doesn't match per the -nr parameter + // - it doesn't have any of the Selfer methods in the file + if regexName.FindStringIndex(td.Name.Name) != nil && + notRegexName.FindStringIndex(td.Name.Name) == nil && + !selferEncTyps[td.Name.Name] && + !selferDecTyps[td.Name.Name] { tv.Types = append(tv.Types, td.Name.Name) } } @@ -254,6 +290,20 @@ func gen1(frunName, tmplStr string, tv interface{}) (frun *os.File, err error) { return } +// copied from ../gen.go (keep in sync). +func stripVendor(s string) string { + // HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later. + // if s contains /vendor/ OR startsWith vendor/, then return everything after it. + const vendorStart = "vendor/" + const vendorInline = "/vendor/" + if i := strings.LastIndex(s, vendorInline); i >= 0 { + s = s[i+len(vendorInline):] + } else if strings.HasPrefix(s, vendorStart) { + s = s[len(vendorStart):] + } + return s +} + func main() { o := flag.String("o", "", "out file") c := flag.String("c", genCodecPath, "codec path") diff --git a/vendor/github.com/ugorji/go/codec/decode.go b/vendor/github.com/ugorji/go/codec/decode.go index e30e8e8c13d..2563668ba75 100644 --- a/vendor/github.com/ugorji/go/codec/decode.go +++ b/vendor/github.com/ugorji/go/codec/decode.go @@ -161,7 +161,9 @@ type DecodeOptions struct { // look them up from a map (than to allocate them afresh). // // Note: Handles will be smart when using the intern functionality. - // So everything will not be interned. + // Every string should not be interned. + // An excellent use-case for interning is struct field names, + // or map keys where key type is string. InternString bool // PreferArrayOverSlice controls whether to decode to an array or a slice. @@ -740,7 +742,8 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { if cr != nil { cr.sendContainerState(containerMapKey) } - rvkencname := stringView(dd.DecodeBytes(f.d.b[:], true, true)) + rvkencnameB := dd.DecodeBytes(f.d.b[:], true, true) + rvkencname := stringView(rvkencnameB) // rvksi := ti.getForEncName(rvkencname) if cr != nil { cr.sendContainerState(containerMapValue) @@ -755,6 +758,7 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { } else { d.structFieldNotFound(-1, rvkencname) } + keepAlive4StringView(rvkencnameB) // maintain ref 4 stringView } } else { for j := 0; !dd.CheckBreak(); j++ { @@ -762,7 +766,8 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { if cr != nil { cr.sendContainerState(containerMapKey) } - rvkencname := stringView(dd.DecodeBytes(f.d.b[:], true, true)) + rvkencnameB := dd.DecodeBytes(f.d.b[:], true, true) + rvkencname := stringView(rvkencnameB) // rvksi := ti.getForEncName(rvkencname) if cr != nil { cr.sendContainerState(containerMapValue) @@ -777,6 +782,7 @@ func (f *decFnInfo) kStruct(rv reflect.Value) { } else { d.structFieldNotFound(-1, rvkencname) } + keepAlive4StringView(rvkencnameB) // maintain ref 4 stringView } } if cr != nil { @@ -1338,6 +1344,7 @@ func (d *Decoder) Reset(r io.Reader) { func (d *Decoder) ResetBytes(in []byte) { // d.s = d.sa[:0] + d.bytes = true d.rb.reset(in) d.r = &d.rb d.resetCommon() @@ -1872,11 +1879,14 @@ func (d *Decoder) errorf(format string, params ...interface{}) { panic(err) } +// Possibly get an interned version of a string +// +// This should mostly be used for map keys, where the key type is string func (d *Decoder) string(v []byte) (s string) { if d.is != nil { - s, ok := d.is[string(v)] // no allocation here. + s, ok := d.is[string(v)] // no allocation here, per go implementation if !ok { - s = string(v) + s = string(v) // new allocation here d.is[s] = s } return s @@ -1884,11 +1894,11 @@ func (d *Decoder) string(v []byte) (s string) { return string(v) // don't return stringView, as we need a real string here. } -func (d *Decoder) intern(s string) { - if d.is != nil { - d.is[s] = s - } -} +// func (d *Decoder) intern(s string) { +// if d.is != nil { +// d.is[s] = s +// } +// } // nextValueBytes returns the next value in the stream as a set of bytes. func (d *Decoder) nextValueBytes() []byte { diff --git a/vendor/github.com/ugorji/go/codec/encode.go b/vendor/github.com/ugorji/go/codec/encode.go index c2cef812ec7..268154d24c8 100644 --- a/vendor/github.com/ugorji/go/codec/encode.go +++ b/vendor/github.com/ugorji/go/codec/encode.go @@ -1027,6 +1027,8 @@ func (e *Encoder) ResetBytes(out *[]byte) { // However, struct values may encode as arrays. This happens when: // - StructToArray Encode option is set, OR // - the tag on the _struct field sets the "toarray" option +// Note that omitempty is ignored when encoding struct values as arrays, +// as an entry must be encoded for each field, to maintain its position. // // Values with types that implement MapBySlice are encoded as stream maps. // @@ -1053,8 +1055,7 @@ func (e *Encoder) ResetBytes(out *[]byte) { // } // // type MyStruct struct { -// _struct bool `codec:",omitempty,toarray"` //set omitempty for every field -// //and encode struct as an array +// _struct bool `codec:",toarray"` //encode struct as an array // } // // The mode of encoding is based on the type of the value. When a value is seen: diff --git a/vendor/github.com/ugorji/go/codec/gen.go b/vendor/github.com/ugorji/go/codec/gen.go index c4944dbff3e..da66921a66c 100644 --- a/vendor/github.com/ugorji/go/codec/gen.go +++ b/vendor/github.com/ugorji/go/codec/gen.go @@ -1653,15 +1653,8 @@ func (x *genV) MethodNamePfx(prefix string, prim bool) string { func genImportPath(t reflect.Type) (s string) { s = t.PkgPath() if genCheckVendor { - // HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later. - // if s contains /vendor/ OR startsWith vendor/, then return everything after it. - const vendorStart = "vendor/" - const vendorInline = "/vendor/" - if i := strings.LastIndex(s, vendorInline); i >= 0 { - s = s[i+len(vendorInline):] - } else if strings.HasPrefix(s, vendorStart) { - s = s[len(vendorStart):] - } + // HACK: always handle vendoring. It should be typically on in go 1.6, 1.7 + s = stripVendor(s) } return } @@ -1884,6 +1877,19 @@ func genInternalSortType(s string, elem bool) string { panic("sorttype: unexpected type: " + s) } +func stripVendor(s string) string { + // HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later. + // if s contains /vendor/ OR startsWith vendor/, then return everything after it. + const vendorStart = "vendor/" + const vendorInline = "/vendor/" + if i := strings.LastIndex(s, vendorInline); i >= 0 { + s = s[i+len(vendorInline):] + } else if strings.HasPrefix(s, vendorStart) { + s = s[len(vendorStart):] + } + return s +} + // var genInternalMu sync.Mutex var genInternalV genInternal var genInternalTmplFuncs template.FuncMap diff --git a/vendor/github.com/ugorji/go/codec/helper_not_unsafe.go b/vendor/github.com/ugorji/go/codec/helper_not_unsafe.go index 8b06a004590..f254b988605 100644 --- a/vendor/github.com/ugorji/go/codec/helper_not_unsafe.go +++ b/vendor/github.com/ugorji/go/codec/helper_not_unsafe.go @@ -8,6 +8,9 @@ package codec // stringView returns a view of the []byte as a string. // In unsafe mode, it doesn't incur allocation and copying caused by conversion. // In regular safe mode, it is an allocation and copy. +// +// Usage: Always maintain a reference to v while result of this call is in use, +// and call keepAlive4BytesView(v) at point where done with view. func stringView(v []byte) string { return string(v) } @@ -15,6 +18,19 @@ func stringView(v []byte) string { // bytesView returns a view of the string as a []byte. // In unsafe mode, it doesn't incur allocation and copying caused by conversion. // In regular safe mode, it is an allocation and copy. +// +// Usage: Always maintain a reference to v while result of this call is in use, +// and call keepAlive4BytesView(v) at point where done with view. func bytesView(v string) []byte { return []byte(v) } + +// keepAlive4BytesView maintains a reference to the input parameter for bytesView. +// +// Usage: call this at point where done with the bytes view. +func keepAlive4BytesView(v string) {} + +// keepAlive4BytesView maintains a reference to the input parameter for stringView. +// +// Usage: call this at point where done with the string view. +func keepAlive4StringView(v []byte) {} diff --git a/vendor/github.com/ugorji/go/codec/helper_unsafe.go b/vendor/github.com/ugorji/go/codec/helper_unsafe.go index 0f596c71aad..6c146f77cd0 100644 --- a/vendor/github.com/ugorji/go/codec/helper_unsafe.go +++ b/vendor/github.com/ugorji/go/codec/helper_unsafe.go @@ -6,10 +6,12 @@ package codec import ( + "runtime" "unsafe" ) // This file has unsafe variants of some helper methods. +// NOTE: See helper_not_unsafe.go for the usage information. type unsafeString struct { Data uintptr @@ -22,9 +24,6 @@ type unsafeSlice struct { Cap int } -// stringView returns a view of the []byte as a string. -// In unsafe mode, it doesn't incur allocation and copying caused by conversion. -// In regular safe mode, it is an allocation and copy. func stringView(v []byte) string { if len(v) == 0 { return "" @@ -35,9 +34,6 @@ func stringView(v []byte) string { return *(*string)(unsafe.Pointer(&sx)) } -// bytesView returns a view of the string as a []byte. -// In unsafe mode, it doesn't incur allocation and copying caused by conversion. -// In regular safe mode, it is an allocation and copy. func bytesView(v string) []byte { if len(v) == 0 { return zeroByteSlice @@ -47,3 +43,11 @@ func bytesView(v string) []byte { bx := unsafeSlice{sx.Data, sx.Len, sx.Len} return *(*[]byte)(unsafe.Pointer(&bx)) } + +func keepAlive4BytesView(v string) { + runtime.KeepAlive(v) +} + +func keepAlive4StringView(v []byte) { + runtime.KeepAlive(v) +} diff --git a/vendor/github.com/ugorji/go/codec/msgpack.go b/vendor/github.com/ugorji/go/codec/msgpack.go index e09d5a04a9f..73097697396 100644 --- a/vendor/github.com/ugorji/go/codec/msgpack.go +++ b/vendor/github.com/ugorji/go/codec/msgpack.go @@ -569,6 +569,9 @@ func (d *msgpackDecDriver) uncacheRead() { } func (d *msgpackDecDriver) ContainerType() (vt valueType) { + if !d.bdRead { + d.readNextBd() + } bd := d.bd if bd == mpNil { return valueTypeNil @@ -621,10 +624,16 @@ func (d *msgpackDecDriver) readContainerLen(ct msgpackContainerType) (clen int) } func (d *msgpackDecDriver) ReadMapStart() int { + if !d.bdRead { + d.readNextBd() + } return d.readContainerLen(msgpackContainerMap) } func (d *msgpackDecDriver) ReadArrayStart() int { + if !d.bdRead { + d.readNextBd() + } return d.readContainerLen(msgpackContainerList) } @@ -727,7 +736,7 @@ func (h *MsgpackHandle) newEncDriver(e *Encoder) encDriver { } func (h *MsgpackHandle) newDecDriver(d *Decoder) decDriver { - return &msgpackDecDriver{d: d, r: d.r, h: h, br: d.bytes} + return &msgpackDecDriver{d: d, h: h, r: d.r, br: d.bytes} } func (e *msgpackEncDriver) reset() { @@ -735,7 +744,7 @@ func (e *msgpackEncDriver) reset() { } func (d *msgpackDecDriver) reset() { - d.r = d.d.r + d.r, d.br = d.d.r, d.d.bytes d.bd, d.bdRead = 0, false } diff --git a/vendor/github.com/ugorji/go/codec/prebuild.sh b/vendor/github.com/ugorji/go/codec/prebuild.sh index 909f4bb0f24..422c1a73424 100755 --- a/vendor/github.com/ugorji/go/codec/prebuild.sh +++ b/vendor/github.com/ugorji/go/codec/prebuild.sh @@ -38,7 +38,7 @@ _build() { return 0 fi - # echo "Running prebuild" + # echo "Running prebuild" if [ "${zbak}" == "1" ] then # echo "Backing up old generated files" @@ -46,12 +46,13 @@ _build() { _gg=".generated.go" [ -e "gen-helper${_gg}" ] && mv gen-helper${_gg} gen-helper${_gg}__${_zts}.bak [ -e "fast-path${_gg}" ] && mv fast-path${_gg} fast-path${_gg}__${_zts}.bak + [ -e "gen${_gg}" ] && mv gen${_gg} gen${_gg}__${_zts}.bak # [ -e "safe${_gg}" ] && mv safe${_gg} safe${_gg}__${_zts}.bak # [ -e "unsafe${_gg}" ] && mv unsafe${_gg} unsafe${_gg}__${_zts}.bak - else - rm -f fast-path.generated.go gen.generated.go gen-helper.generated.go \ - *safe.generated.go *_generated_test.go *.generated_ffjson_expose.go - fi + fi + rm -f gen-helper.generated.go fast-path.generated.go \ + gen.generated.go \ + *safe.generated.go *_generated_test.go *.generated_ffjson_expose.go cat > gen.generated.go <