Adds gopsutil to vendored deps.
This commit is contained in:
parent
3455a4d40e
commit
ee8d373d6a
|
@ -0,0 +1,61 @@
|
|||
gopsutil is distributed under BSD license reproduced below.
|
||||
|
||||
Copyright (c) 2014, WAKAYAMA Shirou
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the gopsutil authors nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
-------
|
||||
internal/common/binary.go in the gopsutil is copied and modifid from golang/encoding/binary.go.
|
||||
|
||||
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,26 @@
|
|||
.PHONY: help check
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
SUBPKGS=cpu disk docker host internal load mem net process
|
||||
|
||||
help: ## Show help
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
check: ## Check
|
||||
errcheck -ignore="Close|Run|Write" ./...
|
||||
golint ./... | egrep -v 'underscores|HttpOnly|should have comment|comment on exported|CamelCase|VM|UID' && exit 1 || exit 0
|
||||
|
||||
BUILD_FAIL_PATTERN=grep -v "exec format error" | grep "build failed" && exit 1 || exit 0
|
||||
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)
|
||||
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)
|
||||
# Operating systems supported for building only (not implemented error if used)
|
||||
GOOS=dragonfly go test ./... | $(BUILD_FAIL_PATTERN)
|
||||
GOOS=netbsd go test ./... | $(BUILD_FAIL_PATTERN)
|
||||
GOOS=solaris go test ./... | $(BUILD_FAIL_PATTERN)
|
||||
@echo 'Successfully built on all known operating systems'
|
|
@ -0,0 +1,318 @@
|
|||
gopsutil: psutil for golang
|
||||
==============================
|
||||
|
||||
.. image:: https://circleci.com/gh/shirou/gopsutil.svg?&style=shield
|
||||
:target: https://circleci.com/gh/shirou/gopsutil
|
||||
|
||||
.. image:: https://coveralls.io/repos/shirou/gopsutil/badge.svg?branch=master
|
||||
:target: https://coveralls.io/r/shirou/gopsutil?branch=master
|
||||
|
||||
.. image:: https://godoc.org/github.com/shirou/gopsutil?status.svg
|
||||
:target: http://godoc.org/github.com/shirou/gopsutil
|
||||
|
||||
This is a port of psutil (http://pythonhosted.org/psutil/). The challenge is porting all
|
||||
psutil functions on some architectures.
|
||||
|
||||
|
||||
.. highlights:: Breaking Changes!
|
||||
|
||||
Breaking changes is introduced at v2. See `issue 174 <https://github.com/shirou/gopsutil/issues/174>`_ .
|
||||
|
||||
|
||||
Migrating to v2
|
||||
-------------------------
|
||||
|
||||
On gopsutil itself, `v2migration.sh <https://github.com/shirou/gopsutil/blob/v2/v2migration.sh>`_ is used for migration. It can not be commonly used, but it may help you with migration.
|
||||
|
||||
|
||||
Tag semantics
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
gopsutil tag policy is almost same as Semantic Versioning, but automatically increase like Ubuntu versioning.
|
||||
|
||||
for example, `v2.16.10` means
|
||||
|
||||
- v2: major version
|
||||
- 16: release year, 2016
|
||||
- 10: release month
|
||||
|
||||
gopsutil aims to keep backwards-compatiblity until major version change.
|
||||
|
||||
Taged at every end of month, but there are only a few commits, it can be skipped.
|
||||
|
||||
|
||||
Available Architectures
|
||||
------------------------------------
|
||||
|
||||
- FreeBSD i386/amd64
|
||||
- Linux i386/amd64/arm(raspberry pi)
|
||||
- Windows/amd64
|
||||
- Darwin/amd64
|
||||
- OpenBDS amd64 (Thank you @mpfz0r!)
|
||||
|
||||
All works are implemented without cgo by porting c struct to golang struct.
|
||||
|
||||
|
||||
Usage
|
||||
---------
|
||||
|
||||
Note: gopsutil v2 breaks compatibility. If you want to stay with compatibility, please use v1 branch and vendoring.
|
||||
|
||||
.. code:: go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/shirou/gopsutil/mem"
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, _ := mem.VirtualMemory()
|
||||
|
||||
// almost every return value is a struct
|
||||
fmt.Printf("Total: %v, Free:%v, UsedPercent:%f%%\n", v.Total, v.Free, v.UsedPercent)
|
||||
|
||||
// convert to JSON. String() is also implemented
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
The output is below.
|
||||
|
||||
::
|
||||
|
||||
Total: 3179569152, Free:284233728, UsedPercent:84.508194%
|
||||
{"total":3179569152,"available":492572672,"used":2895335424,"usedPercent":84.50819439828305, (snip...)}
|
||||
|
||||
You can set an alternative location to :code:`/proc` by setting the :code:`HOST_PROC` environment variable.
|
||||
|
||||
You can set an alternative location to :code:`/sys` by setting the :code:`HOST_SYS` environment variable.
|
||||
|
||||
You can set an alternative location to :code:`/etc` by setting the :code:`HOST_ETC` environment variable.
|
||||
|
||||
Documentation
|
||||
------------------------
|
||||
|
||||
see http://godoc.org/github.com/shirou/gopsutil
|
||||
|
||||
Requirements
|
||||
-----------------
|
||||
|
||||
- go1.5 or above is required.
|
||||
|
||||
|
||||
More Info
|
||||
--------------------
|
||||
|
||||
Several methods have been added which are not present in psutil, but will provide useful information.
|
||||
|
||||
- host/HostInfo() (linux)
|
||||
|
||||
- Hostname
|
||||
- Uptime
|
||||
- Procs
|
||||
- OS (ex: "linux")
|
||||
- Platform (ex: "ubuntu", "arch")
|
||||
- PlatformFamily (ex: "debian")
|
||||
- PlatformVersion (ex: "Ubuntu 13.10")
|
||||
- VirtualizationSystem (ex: "LXC")
|
||||
- VirtualizationRole (ex: "guest"/"host")
|
||||
|
||||
- cpu/CPUInfo() (linux, freebsd)
|
||||
|
||||
- CPU (ex: 0, 1, ...)
|
||||
- VendorID (ex: "GenuineIntel")
|
||||
- Family
|
||||
- Model
|
||||
- Stepping
|
||||
- PhysicalID
|
||||
- CoreID
|
||||
- Cores (ex: 2)
|
||||
- ModelName (ex: "Intel(R) Core(TM) i7-2640M CPU @ 2.80GHz")
|
||||
- Mhz
|
||||
- CacheSize
|
||||
- Flags (ex: "fpu vme de pse tsc msr pae mce cx8 ...")
|
||||
|
||||
- load/LoadAvg() (linux, freebsd)
|
||||
|
||||
- Load1
|
||||
- Load5
|
||||
- Load15
|
||||
|
||||
- docker/GetDockerIDList() (linux only)
|
||||
|
||||
- container id list ([]string)
|
||||
|
||||
- docker/CgroupCPU() (linux only)
|
||||
|
||||
- user
|
||||
- system
|
||||
|
||||
- docker/CgroupMem() (linux only)
|
||||
|
||||
- various status
|
||||
|
||||
- net_protocols (linux only)
|
||||
|
||||
- system wide stats on network protocols (i.e IP, TCP, UDP, etc.)
|
||||
- sourced from /proc/net/snmp
|
||||
|
||||
- iptables nf_conntrack (linux only)
|
||||
|
||||
- system wide stats on netfilter conntrack module
|
||||
- sourced from /proc/sys/net/netfilter/nf_conntrack_count
|
||||
|
||||
Some codes are ported from Ohai. many thanks.
|
||||
|
||||
|
||||
Current Status
|
||||
------------------
|
||||
|
||||
- x: work
|
||||
- b: almost works, but something is broken
|
||||
|
||||
=================== ====== ======= ======= ====== =======
|
||||
name Linux FreeBSD OpenBSD MacOSX Windows
|
||||
cpu_times x x x x x
|
||||
cpu_count x x x x x
|
||||
cpu_percent x x x x x
|
||||
cpu_times_percent x x x x x
|
||||
virtual_memory x x x x x
|
||||
swap_memory x x x x
|
||||
disk_partitions x x x x x
|
||||
disk_io_counters x x x
|
||||
disk_usage x x x x x
|
||||
net_io_counters x x x b x
|
||||
boot_time x x x x x
|
||||
users x x x x x
|
||||
pids x x x x x
|
||||
pid_exists x x x x x
|
||||
net_connections x x
|
||||
net_protocols x
|
||||
net_if_addrs
|
||||
net_if_stats
|
||||
netfilter_conntrack x
|
||||
=================== ====== ======= ======= ====== =======
|
||||
|
||||
Process class
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
================ ===== ======= ======= ====== =======
|
||||
name Linux FreeBSD OpenBSD MacOSX Windows
|
||||
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
|
||||
status x x x x
|
||||
cwd x
|
||||
exe x x x x
|
||||
uids x x x x
|
||||
gids x x x x
|
||||
terminal x x x x
|
||||
io_counters x x x x
|
||||
nice x x x x x
|
||||
num_fds x
|
||||
num_ctx_switches x
|
||||
num_threads x x x x x
|
||||
cpu_times x
|
||||
memory_info x x x x x
|
||||
memory_info_ex x
|
||||
memory_maps x
|
||||
open_files x
|
||||
send_signal x x x x
|
||||
suspend x x x x
|
||||
resume x x x x
|
||||
terminate x x x x x
|
||||
kill x x x x
|
||||
username x
|
||||
ionice
|
||||
rlimit
|
||||
num_handlres
|
||||
threads
|
||||
cpu_percent x x x
|
||||
cpu_affinity
|
||||
memory_percent
|
||||
parent x x x
|
||||
children x x x x
|
||||
connections x x x
|
||||
is_running
|
||||
================ ===== ======= ======= ====== =======
|
||||
|
||||
Original Metrics
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
================== ===== ======= ======= ====== =======
|
||||
item Linux FreeBSD OpenBSD MacOSX Windows
|
||||
**HostInfo**
|
||||
hostname x x x x x
|
||||
uptime x x x x
|
||||
proces x x x
|
||||
os x x x x x
|
||||
platform x x x x
|
||||
platformfamily x x x x
|
||||
virtualization x
|
||||
**CPU**
|
||||
VendorID x x x x x
|
||||
Family x x x x x
|
||||
Model x x x x x
|
||||
Stepping x x x x x
|
||||
PhysicalID x
|
||||
CoreID x
|
||||
Cores x x
|
||||
ModelName x x x x x
|
||||
**LoadAvg**
|
||||
Load1 x x x x
|
||||
Load5 x x x x
|
||||
Load15 x x x x
|
||||
**GetDockerID**
|
||||
container id x no no no no
|
||||
**CgroupsCPU**
|
||||
user x no no no no
|
||||
system x no no no no
|
||||
**CgroupsMem**
|
||||
various x no no no no
|
||||
================== ===== ======= ======= ====== =======
|
||||
|
||||
- future work
|
||||
|
||||
- process_iter
|
||||
- wait_procs
|
||||
- Process class
|
||||
|
||||
- as_dict
|
||||
- wait
|
||||
|
||||
|
||||
License
|
||||
------------
|
||||
|
||||
New BSD License (same as psutil)
|
||||
|
||||
|
||||
Related Works
|
||||
-----------------------
|
||||
|
||||
I have been influenced by the following great works:
|
||||
|
||||
- psutil: http://pythonhosted.org/psutil/
|
||||
- dstat: https://github.com/dagwieers/dstat
|
||||
- gosigar: https://github.com/cloudfoundry/gosigar/
|
||||
- goprocinfo: https://github.com/c9s/goprocinfo
|
||||
- go-ps: https://github.com/mitchellh/go-ps
|
||||
- ohai: https://github.com/opscode/ohai/
|
||||
- bosun: https://github.com/bosun-monitor/bosun/tree/master/cmd/scollector/collectors
|
||||
- mackerel: https://github.com/mackerelio/mackerel-agent/tree/master/metrics
|
||||
|
||||
How to Contribute
|
||||
---------------------------
|
||||
|
||||
1. Fork it
|
||||
2. Create your feature branch (git checkout -b my-new-feature)
|
||||
3. Commit your changes (git commit -am 'Add some feature')
|
||||
4. Push to the branch (git push origin my-new-feature)
|
||||
5. Create new Pull Request
|
||||
|
||||
My English is terrible, so documentation or correcting comments are also
|
||||
welcome.
|
|
@ -0,0 +1,11 @@
|
|||
machine:
|
||||
timezone:
|
||||
Asia/Tokyo
|
||||
test:
|
||||
override:
|
||||
- GOOS=linux GOARCH=amd64 go test -v ./...
|
||||
- GOOS=linux GOARCH=386 go get -v ./...
|
||||
- GOOS=linux GOARCH=arm GOARM=7 go get -v ./...
|
||||
- GOOS=freebsd GOARCH=amd64 go get -v ./...
|
||||
- GOOS=windows GOARCH=amd64 go get -v ./...
|
||||
- GOOS=darwin GOARCH=amd64 go get -v ./...
|
|
@ -0,0 +1,26 @@
|
|||
#/bin/sh
|
||||
|
||||
# see http://www.songmu.jp/riji/entry/2015-01-15-goveralls-multi-package.html
|
||||
|
||||
set -e
|
||||
# cleanup
|
||||
cleanup() {
|
||||
if [ $tmpprof != "" ] && [ -f $tmpprof ]; then
|
||||
rm -f $tmpprof
|
||||
fi
|
||||
exit
|
||||
}
|
||||
trap cleanup INT QUIT TERM EXIT
|
||||
|
||||
# メインの処理
|
||||
prof=${1:-".profile.cov"}
|
||||
echo "mode: count" > $prof
|
||||
gopath1=$(echo $GOPATH | cut -d: -f1)
|
||||
for pkg in $(go list ./...); do
|
||||
tmpprof=$gopath1/src/$pkg/profile.tmp
|
||||
go test -covermode=count -coverprofile=$tmpprof $pkg
|
||||
if [ -f $tmpprof ]; then
|
||||
cat $tmpprof | tail -n +2 >> $prof
|
||||
rm $tmpprof
|
||||
fi
|
||||
done
|
|
@ -0,0 +1 @@
|
|||
package gopsutil
|
|
@ -0,0 +1,50 @@
|
|||
package host
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
var (
|
||||
invoke common.Invoker
|
||||
cachedBootTime = uint64(0)
|
||||
)
|
||||
|
||||
func init() {
|
||||
invoke = common.Invoke{}
|
||||
}
|
||||
|
||||
// A HostInfoStat describes the host status.
|
||||
// This is not in the psutil but it useful.
|
||||
type InfoStat struct {
|
||||
Hostname string `json:"hostname"`
|
||||
Uptime uint64 `json:"uptime"`
|
||||
BootTime uint64 `json:"bootTime"`
|
||||
Procs uint64 `json:"procs"` // number of processes
|
||||
OS string `json:"os"` // ex: freebsd, linux
|
||||
Platform string `json:"platform"` // ex: ubuntu, linuxmint
|
||||
PlatformFamily string `json:"platformFamily"` // ex: debian, rhel
|
||||
PlatformVersion string `json:"platformVersion"` // version of the complete OS
|
||||
KernelVersion string `json:"kernelVersion"` // version of the OS kernel (if available)
|
||||
VirtualizationSystem string `json:"virtualizationSystem"`
|
||||
VirtualizationRole string `json:"virtualizationRole"` // guest or host
|
||||
HostID string `json:"hostid"` // ex: uuid
|
||||
}
|
||||
|
||||
type UserStat struct {
|
||||
User string `json:"user"`
|
||||
Terminal string `json:"terminal"`
|
||||
Host string `json:"host"`
|
||||
Started int `json:"started"`
|
||||
}
|
||||
|
||||
func (h InfoStat) String() string {
|
||||
s, _ := json.Marshal(h)
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func (u UserStat) String() string {
|
||||
s, _ := json.Marshal(u)
|
||||
return string(s)
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
// +build darwin
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
)
|
||||
|
||||
// from utmpx.h
|
||||
const USER_PROCESS = 7
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
PlatformFamily: "darwin",
|
||||
}
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err == nil {
|
||||
ret.Hostname = hostname
|
||||
}
|
||||
|
||||
platform, family, pver, version, err := PlatformInformation()
|
||||
if err == nil {
|
||||
ret.Platform = platform
|
||||
ret.PlatformFamily = family
|
||||
ret.PlatformVersion = pver
|
||||
ret.KernelVersion = version
|
||||
}
|
||||
|
||||
system, role, err := Virtualization()
|
||||
if err == nil {
|
||||
ret.VirtualizationSystem = system
|
||||
ret.VirtualizationRole = role
|
||||
}
|
||||
|
||||
boot, err := BootTime()
|
||||
if err == nil {
|
||||
ret.BootTime = boot
|
||||
ret.Uptime = uptime(boot)
|
||||
}
|
||||
|
||||
procs, err := process.Pids()
|
||||
if err == nil {
|
||||
ret.Procs = uint64(len(procs))
|
||||
}
|
||||
|
||||
values, err := common.DoSysctrl("kern.uuid")
|
||||
if err == nil && len(values) == 1 && values[0] != "" {
|
||||
ret.HostID = values[0]
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
if cachedBootTime != 0 {
|
||||
return cachedBootTime, nil
|
||||
}
|
||||
values, err := common.DoSysctrl("kern.boottime")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014
|
||||
v := strings.Replace(values[2], ",", "", 1)
|
||||
boottime, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cachedBootTime = uint64(boottime)
|
||||
|
||||
return cachedBootTime, nil
|
||||
}
|
||||
|
||||
func uptime(boot uint64) uint64 {
|
||||
return uint64(time.Now().Unix()) - boot
|
||||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
boot, err := BootTime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uptime(boot), nil
|
||||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
utmpfile := "/var/run/utmpx"
|
||||
var ret []UserStat
|
||||
|
||||
file, err := os.Open(utmpfile)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
buf, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
u := Utmpx{}
|
||||
entrySize := int(unsafe.Sizeof(u))
|
||||
count := len(buf) / entrySize
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
b := buf[i*entrySize : i*entrySize+entrySize]
|
||||
|
||||
var u Utmpx
|
||||
br := bytes.NewReader(b)
|
||||
err := binary.Read(br, binary.LittleEndian, &u)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if u.Type != USER_PROCESS {
|
||||
continue
|
||||
}
|
||||
user := UserStat{
|
||||
User: common.IntToString(u.User[:]),
|
||||
Terminal: common.IntToString(u.Line[:]),
|
||||
Host: common.IntToString(u.Host[:]),
|
||||
Started: int(u.Tv.Sec),
|
||||
}
|
||||
ret = append(ret, user)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
||||
}
|
||||
|
||||
func PlatformInformation() (string, string, string, string, error) {
|
||||
platform := ""
|
||||
family := ""
|
||||
version := ""
|
||||
pver := ""
|
||||
|
||||
sw_vers, err := exec.LookPath("sw_vers")
|
||||
if err != nil {
|
||||
return "", "", "", "", err
|
||||
}
|
||||
uname, err := exec.LookPath("uname")
|
||||
if err != nil {
|
||||
return "", "", "", "", err
|
||||
}
|
||||
|
||||
out, err := invoke.Command(uname, "-s")
|
||||
if err == nil {
|
||||
platform = strings.ToLower(strings.TrimSpace(string(out)))
|
||||
}
|
||||
|
||||
out, err = invoke.Command(sw_vers, "-productVersion")
|
||||
if err == nil {
|
||||
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
|
||||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
system := ""
|
||||
role := ""
|
||||
|
||||
return system, role, nil
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_darwin.go
|
||||
|
||||
package host
|
||||
|
||||
type Utmpx struct {
|
||||
User [256]int8
|
||||
ID [4]int8
|
||||
Line [32]int8
|
||||
Pid int32
|
||||
Type int16
|
||||
Pad_cgo_0 [6]byte
|
||||
Tv Timeval
|
||||
Host [256]int8
|
||||
Pad [16]uint32
|
||||
}
|
||||
type Timeval struct {
|
||||
Sec int32
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// +build !darwin,!linux,!freebsd,!openbsd,!windows
|
||||
|
||||
package host
|
||||
|
||||
import "github.com/shirou/gopsutil/internal/common"
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
return nil, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
return 0, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
return 0, common.ErrNotImplementedError
|
||||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
return []UserStat{}, common.ErrNotImplementedError
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
// +build freebsd
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
)
|
||||
|
||||
const (
|
||||
UTNameSize = 16 /* see MAXLOGNAME in <sys/param.h> */
|
||||
UTLineSize = 8
|
||||
UTHostSize = 16
|
||||
)
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
PlatformFamily: "freebsd",
|
||||
}
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err == nil {
|
||||
ret.Hostname = hostname
|
||||
}
|
||||
|
||||
platform, family, version, err := PlatformInformation()
|
||||
if err == nil {
|
||||
ret.Platform = platform
|
||||
ret.PlatformFamily = family
|
||||
ret.PlatformVersion = version
|
||||
ret.KernelVersion = version
|
||||
}
|
||||
|
||||
system, role, err := Virtualization()
|
||||
if err == nil {
|
||||
ret.VirtualizationSystem = system
|
||||
ret.VirtualizationRole = role
|
||||
}
|
||||
|
||||
boot, err := BootTime()
|
||||
if err == nil {
|
||||
ret.BootTime = boot
|
||||
ret.Uptime = uptime(boot)
|
||||
}
|
||||
|
||||
procs, err := process.Pids()
|
||||
if err == nil {
|
||||
ret.Procs = uint64(len(procs))
|
||||
}
|
||||
|
||||
values, err := common.DoSysctrl("kern.hostuuid")
|
||||
if err == nil && len(values) == 1 && values[0] != "" {
|
||||
ret.HostID = values[0]
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
if cachedBootTime != 0 {
|
||||
return cachedBootTime, nil
|
||||
}
|
||||
values, err := common.DoSysctrl("kern.boottime")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014
|
||||
v := strings.Replace(values[2], ",", "", 1)
|
||||
|
||||
boottime, err := strconv.ParseUint(v, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cachedBootTime = boottime
|
||||
|
||||
return boottime, nil
|
||||
}
|
||||
|
||||
func uptime(boot uint64) uint64 {
|
||||
return uint64(time.Now().Unix()) - boot
|
||||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
boot, err := BootTime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uptime(boot), nil
|
||||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
utmpfile := "/var/run/utx.active"
|
||||
if !common.PathExists(utmpfile) {
|
||||
utmpfile = "/var/run/utmp" // before 9.0
|
||||
return getUsersFromUtmp(utmpfile)
|
||||
}
|
||||
|
||||
var ret []UserStat
|
||||
file, err := os.Open(utmpfile)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
buf, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
entrySize := sizeOfUtmpx
|
||||
count := len(buf) / entrySize
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
b := buf[i*sizeOfUtmpx : (i+1)*sizeOfUtmpx]
|
||||
var u Utmpx
|
||||
br := bytes.NewReader(b)
|
||||
err := binary.Read(br, binary.LittleEndian, &u)
|
||||
if err != nil || u.Type != 4 {
|
||||
continue
|
||||
}
|
||||
sec := (binary.LittleEndian.Uint32(u.Tv.Sec[:])) / 2 // TODO:
|
||||
user := UserStat{
|
||||
User: common.IntToString(u.User[:]),
|
||||
Terminal: common.IntToString(u.Line[:]),
|
||||
Host: common.IntToString(u.Host[:]),
|
||||
Started: int(sec),
|
||||
}
|
||||
|
||||
ret = append(ret, user)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
||||
}
|
||||
|
||||
func PlatformInformation() (string, string, string, error) {
|
||||
platform := ""
|
||||
family := ""
|
||||
version := ""
|
||||
uname, err := exec.LookPath("uname")
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
out, err := invoke.Command(uname, "-s")
|
||||
if err == nil {
|
||||
platform = 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, version, nil
|
||||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
system := ""
|
||||
role := ""
|
||||
|
||||
return system, role, nil
|
||||
}
|
||||
|
||||
// before 9.0
|
||||
func getUsersFromUtmp(utmpfile string) ([]UserStat, error) {
|
||||
var ret []UserStat
|
||||
file, err := os.Open(utmpfile)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
buf, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
u := Utmp{}
|
||||
entrySize := int(unsafe.Sizeof(u))
|
||||
count := len(buf) / entrySize
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
b := buf[i*entrySize : i*entrySize+entrySize]
|
||||
var u Utmp
|
||||
br := bytes.NewReader(b)
|
||||
err := binary.Read(br, binary.LittleEndian, &u)
|
||||
if err != nil || u.Time == 0 {
|
||||
continue
|
||||
}
|
||||
user := UserStat{
|
||||
User: common.IntToString(u.Name[:]),
|
||||
Terminal: common.IntToString(u.Line[:]),
|
||||
Host: common.IntToString(u.Host[:]),
|
||||
Started: int(u.Time),
|
||||
}
|
||||
|
||||
ret = append(ret, user)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_freebsd.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x4
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x4
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmpx = 197 // TODO why should 197
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int32
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type Utmp struct {
|
||||
Line [8]int8
|
||||
Name [16]int8
|
||||
Host [16]int8
|
||||
Time int32
|
||||
}
|
||||
|
||||
type Utmpx struct {
|
||||
Type int16
|
||||
Tv Timeval
|
||||
Id [8]int8
|
||||
Pid int32
|
||||
User [32]int8
|
||||
Line [16]int8
|
||||
Host [125]int8
|
||||
// X__ut_spare [64]int8
|
||||
}
|
||||
|
||||
type Timeval struct {
|
||||
Sec [4]byte
|
||||
Usec [3]byte
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_freebsd.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x8
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x8
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmpx = 197 // TODO: why should 197, not 0x118
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int64
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type Utmp struct {
|
||||
Line [8]int8
|
||||
Name [16]int8
|
||||
Host [16]int8
|
||||
Time int32
|
||||
}
|
||||
|
||||
type Utmpx struct {
|
||||
Type int16
|
||||
Tv Timeval
|
||||
Id [8]int8
|
||||
Pid int32
|
||||
User [32]int8
|
||||
Line [16]int8
|
||||
Host [125]int8
|
||||
// Host [128]int8
|
||||
// X__ut_spare [64]int8
|
||||
}
|
||||
|
||||
type Timeval struct {
|
||||
Sec [4]byte
|
||||
Usec [3]byte
|
||||
}
|
|
@ -0,0 +1,522 @@
|
|||
// +build linux
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
)
|
||||
|
||||
type LSB struct {
|
||||
ID string
|
||||
Release string
|
||||
Codename string
|
||||
Description string
|
||||
}
|
||||
|
||||
// from utmp.h
|
||||
const USER_PROCESS = 7
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
}
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err == nil {
|
||||
ret.Hostname = hostname
|
||||
}
|
||||
|
||||
platform, family, version, err := PlatformInformation()
|
||||
if err == nil {
|
||||
ret.Platform = platform
|
||||
ret.PlatformFamily = family
|
||||
ret.PlatformVersion = version
|
||||
}
|
||||
kernelVersion, err := KernelVersion()
|
||||
if err == nil {
|
||||
ret.KernelVersion = kernelVersion
|
||||
}
|
||||
|
||||
system, role, err := Virtualization()
|
||||
if err == nil {
|
||||
ret.VirtualizationSystem = system
|
||||
ret.VirtualizationRole = role
|
||||
}
|
||||
|
||||
boot, err := BootTime()
|
||||
if err == nil {
|
||||
ret.BootTime = boot
|
||||
ret.Uptime = uptime(boot)
|
||||
}
|
||||
|
||||
if numProcs, err := common.NumProcs(); err == nil {
|
||||
ret.Procs = numProcs
|
||||
}
|
||||
|
||||
sysProductUUID := common.HostSys("class/dmi/id/product_uuid")
|
||||
switch {
|
||||
case common.PathExists(sysProductUUID):
|
||||
lines, err := common.ReadLines(sysProductUUID)
|
||||
if err == nil && len(lines) > 0 && lines[0] != "" {
|
||||
ret.HostID = lines[0]
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
values, err := common.DoSysctrl("kernel.random.boot_id")
|
||||
if err == nil && len(values) == 1 && values[0] != "" {
|
||||
ret.HostID = values[0]
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// BootTime returns the system boot time expressed in seconds since the epoch.
|
||||
func BootTime() (uint64, error) {
|
||||
if cachedBootTime != 0 {
|
||||
return cachedBootTime, nil
|
||||
}
|
||||
filename := common.HostProc("stat")
|
||||
lines, err := common.ReadLines(filename)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "btime") {
|
||||
f := strings.Fields(line)
|
||||
if len(f) != 2 {
|
||||
return 0, fmt.Errorf("wrong btime format")
|
||||
}
|
||||
b, err := strconv.ParseInt(f[1], 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cachedBootTime = uint64(b)
|
||||
return cachedBootTime, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("could not find btime")
|
||||
}
|
||||
|
||||
func uptime(boot uint64) uint64 {
|
||||
return uint64(time.Now().Unix()) - boot
|
||||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
boot, err := BootTime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uptime(boot), nil
|
||||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
utmpfile := "/var/run/utmp"
|
||||
|
||||
file, err := os.Open(utmpfile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
count := len(buf) / sizeOfUtmp
|
||||
|
||||
ret := make([]UserStat, 0, count)
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
b := buf[i*sizeOfUtmp : (i+1)*sizeOfUtmp]
|
||||
|
||||
var u utmp
|
||||
br := bytes.NewReader(b)
|
||||
err := binary.Read(br, binary.LittleEndian, &u)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if u.Type != USER_PROCESS {
|
||||
continue
|
||||
}
|
||||
user := UserStat{
|
||||
User: common.IntToString(u.User[:]),
|
||||
Terminal: common.IntToString(u.Line[:]),
|
||||
Host: common.IntToString(u.Host[:]),
|
||||
Started: int(u.Tv.Sec),
|
||||
}
|
||||
ret = append(ret, user)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
|
||||
}
|
||||
|
||||
func getOSRelease() (platform string, version string, err error) {
|
||||
contents, err := common.ReadLines(common.HostEtc("os-release"))
|
||||
if err != nil {
|
||||
return "", "", nil // return empty
|
||||
}
|
||||
for _, line := range contents {
|
||||
field := strings.Split(line, "=")
|
||||
if len(field) < 2 {
|
||||
continue
|
||||
}
|
||||
switch field[0] {
|
||||
case "ID": // use ID for lowercase
|
||||
platform = field[1]
|
||||
case "VERSION":
|
||||
version = field[1]
|
||||
}
|
||||
}
|
||||
return platform, version, nil
|
||||
}
|
||||
|
||||
func getLSB() (*LSB, error) {
|
||||
ret := &LSB{}
|
||||
if common.PathExists(common.HostEtc("lsb-release")) {
|
||||
contents, err := common.ReadLines(common.HostEtc("lsb-release"))
|
||||
if err != nil {
|
||||
return ret, err // return empty
|
||||
}
|
||||
for _, line := range contents {
|
||||
field := strings.Split(line, "=")
|
||||
if len(field) < 2 {
|
||||
continue
|
||||
}
|
||||
switch field[0] {
|
||||
case "DISTRIB_ID":
|
||||
ret.ID = field[1]
|
||||
case "DISTRIB_RELEASE":
|
||||
ret.Release = field[1]
|
||||
case "DISTRIB_CODENAME":
|
||||
ret.Codename = field[1]
|
||||
case "DISTRIB_DESCRIPTION":
|
||||
ret.Description = field[1]
|
||||
}
|
||||
}
|
||||
} else if common.PathExists("/usr/bin/lsb_release") {
|
||||
lsb_release, err := exec.LookPath("/usr/bin/lsb_release")
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
out, err := invoke.Command(lsb_release)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
for _, line := range strings.Split(string(out), "\n") {
|
||||
field := strings.Split(line, ":")
|
||||
if len(field) < 2 {
|
||||
continue
|
||||
}
|
||||
switch field[0] {
|
||||
case "Distributor ID":
|
||||
ret.ID = field[1]
|
||||
case "Release":
|
||||
ret.Release = field[1]
|
||||
case "Codename":
|
||||
ret.Codename = field[1]
|
||||
case "Description":
|
||||
ret.Description = field[1]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func PlatformInformation() (platform string, family string, version string, err error) {
|
||||
|
||||
lsb, err := getLSB()
|
||||
if err != nil {
|
||||
lsb = &LSB{}
|
||||
}
|
||||
|
||||
if common.PathExists(common.HostEtc("oracle-release")) {
|
||||
platform = "oracle"
|
||||
contents, err := common.ReadLines(common.HostEtc("oracle-release"))
|
||||
if err == nil {
|
||||
version = getRedhatishVersion(contents)
|
||||
}
|
||||
|
||||
} else if common.PathExists(common.HostEtc("enterprise-release")) {
|
||||
platform = "oracle"
|
||||
contents, err := common.ReadLines(common.HostEtc("enterprise-release"))
|
||||
if err == nil {
|
||||
version = getRedhatishVersion(contents)
|
||||
}
|
||||
} else if common.PathExists(common.HostEtc("debian_version")) {
|
||||
if lsb.ID == "Ubuntu" {
|
||||
platform = "ubuntu"
|
||||
version = lsb.Release
|
||||
} else if lsb.ID == "LinuxMint" {
|
||||
platform = "linuxmint"
|
||||
version = lsb.Release
|
||||
} else {
|
||||
if common.PathExists("/usr/bin/raspi-config") {
|
||||
platform = "raspbian"
|
||||
} else {
|
||||
platform = "debian"
|
||||
}
|
||||
contents, err := common.ReadLines(common.HostEtc("debian_version"))
|
||||
if err == nil {
|
||||
version = contents[0]
|
||||
}
|
||||
}
|
||||
} else if common.PathExists(common.HostEtc("redhat-release")) {
|
||||
contents, err := common.ReadLines(common.HostEtc("redhat-release"))
|
||||
if err == nil {
|
||||
version = getRedhatishVersion(contents)
|
||||
platform = getRedhatishPlatform(contents)
|
||||
}
|
||||
} else if common.PathExists(common.HostEtc("system-release")) {
|
||||
contents, err := common.ReadLines(common.HostEtc("system-release"))
|
||||
if err == nil {
|
||||
version = getRedhatishVersion(contents)
|
||||
platform = getRedhatishPlatform(contents)
|
||||
}
|
||||
} else if common.PathExists(common.HostEtc("gentoo-release")) {
|
||||
platform = "gentoo"
|
||||
contents, err := common.ReadLines(common.HostEtc("gentoo-release"))
|
||||
if err == nil {
|
||||
version = getRedhatishVersion(contents)
|
||||
}
|
||||
} else if common.PathExists(common.HostEtc("SuSE-release")) {
|
||||
contents, err := common.ReadLines(common.HostEtc("SuSE-release"))
|
||||
if err == nil {
|
||||
version = getSuseVersion(contents)
|
||||
platform = getSusePlatform(contents)
|
||||
}
|
||||
// TODO: slackware detecion
|
||||
} else if common.PathExists(common.HostEtc("arch-release")) {
|
||||
platform = "arch"
|
||||
version = lsb.Release
|
||||
} else if common.PathExists(common.HostEtc("alpine-release")) {
|
||||
platform = "alpine"
|
||||
contents, err := common.ReadLines(common.HostEtc("alpine-release"))
|
||||
if err == nil && len(contents) > 0 {
|
||||
version = contents[0]
|
||||
}
|
||||
} else if common.PathExists(common.HostEtc("os-release")) {
|
||||
p, v, err := getOSRelease()
|
||||
if err == nil {
|
||||
platform = p
|
||||
version = v
|
||||
}
|
||||
} else if lsb.ID == "RedHat" {
|
||||
platform = "redhat"
|
||||
version = lsb.Release
|
||||
} else if lsb.ID == "Amazon" {
|
||||
platform = "amazon"
|
||||
version = lsb.Release
|
||||
} else if lsb.ID == "ScientificSL" {
|
||||
platform = "scientific"
|
||||
version = lsb.Release
|
||||
} else if lsb.ID == "XenServer" {
|
||||
platform = "xenserver"
|
||||
version = lsb.Release
|
||||
} else if lsb.ID != "" {
|
||||
platform = strings.ToLower(lsb.ID)
|
||||
version = lsb.Release
|
||||
}
|
||||
|
||||
switch platform {
|
||||
case "debian", "ubuntu", "linuxmint", "raspbian":
|
||||
family = "debian"
|
||||
case "fedora":
|
||||
family = "fedora"
|
||||
case "oracle", "centos", "redhat", "scientific", "enterpriseenterprise", "amazon", "xenserver", "cloudlinux", "ibm_powerkvm":
|
||||
family = "rhel"
|
||||
case "suse", "opensuse":
|
||||
family = "suse"
|
||||
case "gentoo":
|
||||
family = "gentoo"
|
||||
case "slackware":
|
||||
family = "slackware"
|
||||
case "arch":
|
||||
family = "arch"
|
||||
case "exherbo":
|
||||
family = "exherbo"
|
||||
case "alpine":
|
||||
family = "alpine"
|
||||
case "coreos":
|
||||
family = "coreos"
|
||||
}
|
||||
|
||||
return platform, family, version, nil
|
||||
|
||||
}
|
||||
|
||||
func KernelVersion() (version string, err error) {
|
||||
filename := common.HostProc("sys/kernel/osrelease")
|
||||
if common.PathExists(filename) {
|
||||
contents, err := common.ReadLines(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(contents) > 0 {
|
||||
version = contents[0]
|
||||
}
|
||||
}
|
||||
|
||||
return version, nil
|
||||
}
|
||||
|
||||
func getRedhatishVersion(contents []string) string {
|
||||
c := strings.ToLower(strings.Join(contents, ""))
|
||||
|
||||
if strings.Contains(c, "rawhide") {
|
||||
return "rawhide"
|
||||
}
|
||||
if matches := regexp.MustCompile(`release (\d[\d.]*)`).FindStringSubmatch(c); matches != nil {
|
||||
return matches[1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getRedhatishPlatform(contents []string) string {
|
||||
c := strings.ToLower(strings.Join(contents, ""))
|
||||
|
||||
if strings.Contains(c, "red hat") {
|
||||
return "redhat"
|
||||
}
|
||||
f := strings.Split(c, " ")
|
||||
|
||||
return f[0]
|
||||
}
|
||||
|
||||
func getSuseVersion(contents []string) string {
|
||||
version := ""
|
||||
for _, line := range contents {
|
||||
if matches := regexp.MustCompile(`VERSION = ([\d.]+)`).FindStringSubmatch(line); matches != nil {
|
||||
version = matches[1]
|
||||
} else if matches := regexp.MustCompile(`PATCHLEVEL = ([\d]+)`).FindStringSubmatch(line); matches != nil {
|
||||
version = version + "." + matches[1]
|
||||
}
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
||||
func getSusePlatform(contents []string) string {
|
||||
c := strings.ToLower(strings.Join(contents, ""))
|
||||
if strings.Contains(c, "opensuse") {
|
||||
return "opensuse"
|
||||
}
|
||||
return "suse"
|
||||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
var system string
|
||||
var role string
|
||||
|
||||
filename := common.HostProc("xen")
|
||||
if common.PathExists(filename) {
|
||||
system = "xen"
|
||||
role = "guest" // assume guest
|
||||
|
||||
if common.PathExists(filename + "/capabilities") {
|
||||
contents, err := common.ReadLines(filename + "/capabilities")
|
||||
if err == nil {
|
||||
if common.StringsContains(contents, "control_d") {
|
||||
role = "host"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filename = common.HostProc("modules")
|
||||
if common.PathExists(filename) {
|
||||
contents, err := common.ReadLines(filename)
|
||||
if err == nil {
|
||||
if common.StringsContains(contents, "kvm") {
|
||||
system = "kvm"
|
||||
role = "host"
|
||||
} else if common.StringsContains(contents, "vboxdrv") {
|
||||
system = "vbox"
|
||||
role = "host"
|
||||
} else if common.StringsContains(contents, "vboxguest") {
|
||||
system = "vbox"
|
||||
role = "guest"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filename = common.HostProc("cpuinfo")
|
||||
if common.PathExists(filename) {
|
||||
contents, err := common.ReadLines(filename)
|
||||
if err == nil {
|
||||
if common.StringsContains(contents, "QEMU Virtual CPU") ||
|
||||
common.StringsContains(contents, "Common KVM processor") ||
|
||||
common.StringsContains(contents, "Common 32-bit KVM processor") {
|
||||
system = "kvm"
|
||||
role = "guest"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filename = common.HostProc()
|
||||
if common.PathExists(filename + "/bc/0") {
|
||||
system = "openvz"
|
||||
role = "host"
|
||||
} else if common.PathExists(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 err == nil {
|
||||
|
||||
if common.StringsContains(contents, "s_context:") ||
|
||||
common.StringsContains(contents, "VxID:") {
|
||||
system = "linux-vserver"
|
||||
}
|
||||
// TODO: guest or host
|
||||
}
|
||||
}
|
||||
|
||||
if common.PathExists(filename + "/self/cgroup") {
|
||||
contents, err := common.ReadLines(filename + "/self/cgroup")
|
||||
if err == nil {
|
||||
if common.StringsContains(contents, "lxc") {
|
||||
system = "lxc"
|
||||
role = "guest"
|
||||
} else if common.StringsContains(contents, "docker") {
|
||||
system = "docker"
|
||||
role = "guest"
|
||||
} else if common.StringsContains(contents, "machine-rkt") {
|
||||
system = "rkt"
|
||||
role = "guest"
|
||||
} else if common.PathExists("/usr/bin/lxc-version") {
|
||||
system = "lxc"
|
||||
role = "host"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if common.PathExists(common.HostEtc("os-release")) {
|
||||
p, _, err := getOSRelease()
|
||||
if err == nil && p == "coreos" {
|
||||
system = "rkt" // Is it true?
|
||||
role = "host"
|
||||
}
|
||||
}
|
||||
return system, role, nil
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// ATTENTION - FILE MANUAL FIXED AFTER CGO.
|
||||
// Fixed line: Tv _Ctype_struct_timeval -> Tv UtTv
|
||||
// Created by cgo -godefs, MANUAL FIXED
|
||||
// cgo -godefs types_linux.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x4
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x4
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmp = 0x180
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int32
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type utmp struct {
|
||||
Type int16
|
||||
Pad_cgo_0 [2]byte
|
||||
Pid int32
|
||||
Line [32]int8
|
||||
ID [4]int8
|
||||
User [32]int8
|
||||
Host [256]int8
|
||||
Exit exit_status
|
||||
Session int32
|
||||
Tv UtTv
|
||||
Addr_v6 [4]int32
|
||||
X__unused [20]int8
|
||||
}
|
||||
type exit_status struct {
|
||||
Termination int16
|
||||
Exit int16
|
||||
}
|
||||
type UtTv struct {
|
||||
Sec int32
|
||||
Usec int32
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_linux.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x8
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x8
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmp = 0x180
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int64
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type utmp struct {
|
||||
Type int16
|
||||
Pad_cgo_0 [2]byte
|
||||
Pid int32
|
||||
Line [32]int8
|
||||
Id [4]int8
|
||||
User [32]int8
|
||||
Host [256]int8
|
||||
Exit exit_status
|
||||
Session int32
|
||||
Tv _Ctype_struct___0
|
||||
Addr_v6 [4]int32
|
||||
X__glibc_reserved [20]int8
|
||||
}
|
||||
type exit_status struct {
|
||||
Termination int16
|
||||
Exit int16
|
||||
}
|
||||
type timeval struct {
|
||||
Sec int64
|
||||
Usec int64
|
||||
}
|
||||
|
||||
type _Ctype_struct___0 struct {
|
||||
Sec int32
|
||||
Usec int32
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_linux.go | sed "s/uint8/int8/g"
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x4
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x4
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmp = 0x180
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int32
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type utmp struct {
|
||||
Type int16
|
||||
Pad_cgo_0 [2]byte
|
||||
Pid int32
|
||||
Line [32]int8
|
||||
Id [4]int8
|
||||
User [32]int8
|
||||
Host [256]int8
|
||||
Exit exit_status
|
||||
Session int32
|
||||
Tv timeval
|
||||
Addr_v6 [4]int32
|
||||
X__glibc_reserved [20]int8
|
||||
}
|
||||
type exit_status struct {
|
||||
Termination int16
|
||||
Exit int16
|
||||
}
|
||||
type timeval struct {
|
||||
Sec int32
|
||||
Usec int32
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_linux.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x8
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x8
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmp = 0x180
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int64
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type utmp struct {
|
||||
Type int16
|
||||
Pad_cgo_0 [2]byte
|
||||
Pid int32
|
||||
Line [32]int8
|
||||
Id [4]int8
|
||||
User [32]int8
|
||||
Host [256]int8
|
||||
Exit exit_status
|
||||
Session int32
|
||||
Tv timeval
|
||||
Addr_v6 [4]int32
|
||||
X__glibc_reserved [20]int8
|
||||
}
|
||||
type exit_status struct {
|
||||
Termination int16
|
||||
Exit int16
|
||||
}
|
||||
type timeval struct {
|
||||
Sec int64
|
||||
Usec int64
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// +build linux
|
||||
// +build ppc64le
|
||||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_linux.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x8
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x8
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmp = 0x180
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int64
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type utmp struct {
|
||||
Type int16
|
||||
Pad_cgo_0 [2]byte
|
||||
Pid int32
|
||||
Line [32]int8
|
||||
Id [4]int8
|
||||
User [32]int8
|
||||
Host [256]int8
|
||||
Exit exit_status
|
||||
Session int32
|
||||
Tv timeval
|
||||
Addr_v6 [4]int32
|
||||
X__glibc_reserved [20]int8
|
||||
}
|
||||
type exit_status struct {
|
||||
Termination int16
|
||||
Exit int16
|
||||
}
|
||||
type timeval struct {
|
||||
Sec int64
|
||||
Usec int64
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// +build linux
|
||||
// +build s390x
|
||||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_linux.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x8
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x8
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmp = 0x180
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int64
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type utmp struct {
|
||||
Type int16
|
||||
Pad_cgo_0 [2]byte
|
||||
Pid int32
|
||||
Line [32]int8
|
||||
Id [4]int8
|
||||
User [32]int8
|
||||
Host [256]int8
|
||||
Exit exit_status
|
||||
Session int32
|
||||
Tv timeval
|
||||
Addr_v6 [4]int32
|
||||
X__glibc_reserved [20]int8
|
||||
}
|
||||
type exit_status struct {
|
||||
Termination int16
|
||||
Exit int16
|
||||
}
|
||||
type timeval struct {
|
||||
Sec int64
|
||||
Usec int64
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
// +build openbsd
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
)
|
||||
|
||||
const (
|
||||
UTNameSize = 32 /* see MAXLOGNAME in <sys/param.h> */
|
||||
UTLineSize = 8
|
||||
UTHostSize = 16
|
||||
)
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
PlatformFamily: "openbsd",
|
||||
}
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err == nil {
|
||||
ret.Hostname = hostname
|
||||
}
|
||||
|
||||
platform, family, version, err := PlatformInformation()
|
||||
if err == nil {
|
||||
ret.Platform = platform
|
||||
ret.PlatformFamily = family
|
||||
ret.PlatformVersion = version
|
||||
}
|
||||
system, role, err := Virtualization()
|
||||
if err == nil {
|
||||
ret.VirtualizationSystem = system
|
||||
ret.VirtualizationRole = role
|
||||
}
|
||||
|
||||
procs, err := process.Pids()
|
||||
if err == nil {
|
||||
ret.Procs = uint64(len(procs))
|
||||
}
|
||||
|
||||
boot, err := BootTime()
|
||||
if err == nil {
|
||||
ret.BootTime = boot
|
||||
ret.Uptime = uptime(boot)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
val, err := common.DoSysctrl("kern.boottime")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
boottime, err := strconv.ParseUint(val[0], 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return boottime, nil
|
||||
}
|
||||
|
||||
func uptime(boot uint64) uint64 {
|
||||
return uint64(time.Now().Unix()) - boot
|
||||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
boot, err := BootTime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uptime(boot), nil
|
||||
}
|
||||
|
||||
func PlatformInformation() (string, string, string, error) {
|
||||
platform := ""
|
||||
family := ""
|
||||
version := ""
|
||||
uname, err := exec.LookPath("uname")
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
out, err := invoke.Command(uname, "-s")
|
||||
if err == nil {
|
||||
platform = 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, version, nil
|
||||
}
|
||||
|
||||
func Virtualization() (string, string, error) {
|
||||
system := ""
|
||||
role := ""
|
||||
|
||||
return system, role, nil
|
||||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
var ret []UserStat
|
||||
utmpfile := "/var/run/utmp"
|
||||
file, err := os.Open(utmpfile)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
buf, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
u := Utmp{}
|
||||
entrySize := int(unsafe.Sizeof(u))
|
||||
count := len(buf) / entrySize
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
b := buf[i*entrySize : i*entrySize+entrySize]
|
||||
var u Utmp
|
||||
br := bytes.NewReader(b)
|
||||
err := binary.Read(br, binary.LittleEndian, &u)
|
||||
if err != nil || u.Time == 0 {
|
||||
continue
|
||||
}
|
||||
user := UserStat{
|
||||
User: common.IntToString(u.Name[:]),
|
||||
Terminal: common.IntToString(u.Line[:]),
|
||||
Host: common.IntToString(u.Host[:]),
|
||||
Started: int(u.Time),
|
||||
}
|
||||
|
||||
ret = append(ret, user)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_openbsd.go
|
||||
|
||||
package host
|
||||
|
||||
const (
|
||||
sizeofPtr = 0x8
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x8
|
||||
sizeofLongLong = 0x8
|
||||
sizeOfUtmp = 0x130
|
||||
)
|
||||
|
||||
type (
|
||||
_C_short int16
|
||||
_C_int int32
|
||||
_C_long int64
|
||||
_C_long_long int64
|
||||
)
|
||||
|
||||
type Utmp struct {
|
||||
Line [8]int8
|
||||
Name [32]int8
|
||||
Host [256]int8
|
||||
Time int64
|
||||
}
|
||||
type Timeval struct {
|
||||
Sec int64
|
||||
Usec int64
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
// +build windows
|
||||
|
||||
package host
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/StackExchange/wmi"
|
||||
|
||||
"github.com/shirou/gopsutil/internal/common"
|
||||
process "github.com/shirou/gopsutil/process"
|
||||
)
|
||||
|
||||
var (
|
||||
procGetSystemTimeAsFileTime = common.Modkernel32.NewProc("GetSystemTimeAsFileTime")
|
||||
osInfo *Win32_OperatingSystem
|
||||
)
|
||||
|
||||
type Win32_OperatingSystem struct {
|
||||
Version string
|
||||
Caption string
|
||||
ProductType uint32
|
||||
BuildNumber string
|
||||
LastBootUpTime time.Time
|
||||
}
|
||||
|
||||
func Info() (*InfoStat, error) {
|
||||
ret := &InfoStat{
|
||||
OS: runtime.GOOS,
|
||||
}
|
||||
|
||||
hostname, err := os.Hostname()
|
||||
if err == nil {
|
||||
ret.Hostname = hostname
|
||||
}
|
||||
|
||||
platform, family, version, err := PlatformInformation()
|
||||
if err == nil {
|
||||
ret.Platform = platform
|
||||
ret.PlatformFamily = family
|
||||
ret.PlatformVersion = version
|
||||
} else {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
boot, err := BootTime()
|
||||
if err == nil {
|
||||
ret.BootTime = boot
|
||||
ret.Uptime, _ = Uptime()
|
||||
}
|
||||
|
||||
procs, err := process.Pids()
|
||||
if err == nil {
|
||||
ret.Procs = uint64(len(procs))
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func GetOSInfo() (Win32_OperatingSystem, error) {
|
||||
var dst []Win32_OperatingSystem
|
||||
q := wmi.CreateQuery(&dst, "")
|
||||
err := wmi.Query(q, &dst)
|
||||
if err != nil {
|
||||
return Win32_OperatingSystem{}, err
|
||||
}
|
||||
|
||||
osInfo = &dst[0]
|
||||
|
||||
return dst[0], nil
|
||||
}
|
||||
|
||||
func Uptime() (uint64, error) {
|
||||
if osInfo == nil {
|
||||
_, err := GetOSInfo()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
now := time.Now()
|
||||
t := osInfo.LastBootUpTime.Local()
|
||||
return uint64(now.Sub(t).Seconds()), nil
|
||||
}
|
||||
|
||||
func bootTime(up uint64) uint64 {
|
||||
return uint64(time.Now().Unix()) - up
|
||||
}
|
||||
|
||||
func BootTime() (uint64, error) {
|
||||
if cachedBootTime != 0 {
|
||||
return cachedBootTime, nil
|
||||
}
|
||||
up, err := Uptime()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cachedBootTime = bootTime(up)
|
||||
return cachedBootTime, nil
|
||||
}
|
||||
|
||||
func PlatformInformation() (platform string, family string, version string, err error) {
|
||||
if osInfo == nil {
|
||||
_, err = GetOSInfo()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Platform
|
||||
platform = strings.Trim(osInfo.Caption, " ")
|
||||
|
||||
// PlatformFamily
|
||||
switch osInfo.ProductType {
|
||||
case 1:
|
||||
family = "Standalone Workstation"
|
||||
case 2:
|
||||
family = "Server (Domain Controller)"
|
||||
case 3:
|
||||
family = "Server"
|
||||
}
|
||||
|
||||
// Platform Version
|
||||
version = fmt.Sprintf("%s Build %s", osInfo.Version, osInfo.BuildNumber)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func Users() ([]UserStat, error) {
|
||||
|
||||
var ret []UserStat
|
||||
|
||||
return ret, nil
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// +build ignore
|
||||
// plus hand editing about timeval
|
||||
|
||||
/*
|
||||
Input to cgo -godefs.
|
||||
*/
|
||||
|
||||
package host
|
||||
|
||||
/*
|
||||
#include <sys/time.h>
|
||||
#include <utmpx.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type Utmpx C.struct_utmpx
|
||||
type Timeval C.struct_timeval
|
|
@ -0,0 +1,44 @@
|
|||
// +build ignore
|
||||
|
||||
/*
|
||||
Input to cgo -godefs.
|
||||
*/
|
||||
|
||||
package host
|
||||
|
||||
/*
|
||||
#define KERNEL
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <utmpx.h>
|
||||
|
||||
enum {
|
||||
sizeofPtr = sizeof(void*),
|
||||
};
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Machine characteristics; for internal use.
|
||||
|
||||
const (
|
||||
sizeofPtr = C.sizeofPtr
|
||||
sizeofShort = C.sizeof_short
|
||||
sizeofInt = C.sizeof_int
|
||||
sizeofLong = C.sizeof_long
|
||||
sizeofLongLong = C.sizeof_longlong
|
||||
sizeOfUtmpx = C.sizeof_struct_utmpx
|
||||
)
|
||||
|
||||
// Basic types
|
||||
|
||||
type (
|
||||
_C_short C.short
|
||||
_C_int C.int
|
||||
_C_long C.long
|
||||
_C_long_long C.longlong
|
||||
)
|
||||
|
||||
type Utmp C.struct_utmp
|
||||
type Utmpx C.struct_utmpx
|
||||
type Timeval C.struct_timeval
|
|
@ -0,0 +1,42 @@
|
|||
// +build ignore
|
||||
|
||||
/*
|
||||
Input to cgo -godefs.
|
||||
*/
|
||||
|
||||
package host
|
||||
|
||||
/*
|
||||
#include <sys/types.h>
|
||||
#include <utmp.h>
|
||||
|
||||
enum {
|
||||
sizeofPtr = sizeof(void*),
|
||||
};
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Machine characteristics; for internal use.
|
||||
|
||||
const (
|
||||
sizeofPtr = C.sizeofPtr
|
||||
sizeofShort = C.sizeof_short
|
||||
sizeofInt = C.sizeof_int
|
||||
sizeofLong = C.sizeof_long
|
||||
sizeofLongLong = C.sizeof_longlong
|
||||
sizeOfUtmp = C.sizeof_struct_utmp
|
||||
)
|
||||
|
||||
// Basic types
|
||||
|
||||
type (
|
||||
_C_short C.short
|
||||
_C_int C.int
|
||||
_C_long C.long
|
||||
_C_long_long C.longlong
|
||||
)
|
||||
|
||||
type utmp C.struct_utmp
|
||||
type exit_status C.struct_exit_status
|
||||
type timeval C.struct_timeval
|
|
@ -0,0 +1,43 @@
|
|||
// +build ignore
|
||||
|
||||
/*
|
||||
Input to cgo -godefs.
|
||||
*/
|
||||
|
||||
package host
|
||||
|
||||
/*
|
||||
#define KERNEL
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <utmp.h>
|
||||
|
||||
enum {
|
||||
sizeofPtr = sizeof(void*),
|
||||
};
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Machine characteristics; for internal use.
|
||||
|
||||
const (
|
||||
sizeofPtr = C.sizeofPtr
|
||||
sizeofShort = C.sizeof_short
|
||||
sizeofInt = C.sizeof_int
|
||||
sizeofLong = C.sizeof_long
|
||||
sizeofLongLong = C.sizeof_longlong
|
||||
sizeOfUtmp = C.sizeof_struct_utmp
|
||||
)
|
||||
|
||||
// Basic types
|
||||
|
||||
type (
|
||||
_C_short C.short
|
||||
_C_int C.int
|
||||
_C_long C.long
|
||||
_C_long_long C.longlong
|
||||
)
|
||||
|
||||
type Utmp C.struct_utmp
|
||||
type Timeval C.struct_timeval
|
|
@ -0,0 +1,634 @@
|
|||
package common
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package binary implements simple translation between numbers and byte
|
||||
// sequences and encoding and decoding of varints.
|
||||
//
|
||||
// Numbers are translated by reading and writing fixed-size values.
|
||||
// A fixed-size value is either a fixed-size arithmetic
|
||||
// type (int8, uint8, int16, float32, complex64, ...)
|
||||
// or an array or struct containing only fixed-size values.
|
||||
//
|
||||
// The varint functions encode and decode single integer values using
|
||||
// a variable-length encoding; smaller values require fewer bytes.
|
||||
// For a specification, see
|
||||
// http://code.google.com/apis/protocolbuffers/docs/encoding.html.
|
||||
//
|
||||
// This package favors simplicity over efficiency. Clients that require
|
||||
// high-performance serialization, especially for large data structures,
|
||||
// should look at more advanced solutions such as the encoding/gob
|
||||
// package or protocol buffers.
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// A ByteOrder specifies how to convert byte sequences into
|
||||
// 16-, 32-, or 64-bit unsigned integers.
|
||||
type ByteOrder interface {
|
||||
Uint16([]byte) uint16
|
||||
Uint32([]byte) uint32
|
||||
Uint64([]byte) uint64
|
||||
PutUint16([]byte, uint16)
|
||||
PutUint32([]byte, uint32)
|
||||
PutUint64([]byte, uint64)
|
||||
String() string
|
||||
}
|
||||
|
||||
// LittleEndian is the little-endian implementation of ByteOrder.
|
||||
var LittleEndian littleEndian
|
||||
|
||||
// BigEndian is the big-endian implementation of ByteOrder.
|
||||
var BigEndian bigEndian
|
||||
|
||||
type littleEndian struct{}
|
||||
|
||||
func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
|
||||
|
||||
func (littleEndian) PutUint16(b []byte, v uint16) {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
}
|
||||
|
||||
func (littleEndian) Uint32(b []byte) uint32 {
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
||||
func (littleEndian) PutUint32(b []byte, v uint32) {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
}
|
||||
|
||||
func (littleEndian) Uint64(b []byte) uint64 {
|
||||
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
|
||||
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
|
||||
}
|
||||
|
||||
func (littleEndian) PutUint64(b []byte, v uint64) {
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
b[4] = byte(v >> 32)
|
||||
b[5] = byte(v >> 40)
|
||||
b[6] = byte(v >> 48)
|
||||
b[7] = byte(v >> 56)
|
||||
}
|
||||
|
||||
func (littleEndian) String() string { return "LittleEndian" }
|
||||
|
||||
func (littleEndian) GoString() string { return "binary.LittleEndian" }
|
||||
|
||||
type bigEndian struct{}
|
||||
|
||||
func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
|
||||
|
||||
func (bigEndian) PutUint16(b []byte, v uint16) {
|
||||
b[0] = byte(v >> 8)
|
||||
b[1] = byte(v)
|
||||
}
|
||||
|
||||
func (bigEndian) Uint32(b []byte) uint32 {
|
||||
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
|
||||
}
|
||||
|
||||
func (bigEndian) PutUint32(b []byte, v uint32) {
|
||||
b[0] = byte(v >> 24)
|
||||
b[1] = byte(v >> 16)
|
||||
b[2] = byte(v >> 8)
|
||||
b[3] = byte(v)
|
||||
}
|
||||
|
||||
func (bigEndian) Uint64(b []byte) uint64 {
|
||||
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
|
||||
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
|
||||
}
|
||||
|
||||
func (bigEndian) PutUint64(b []byte, v uint64) {
|
||||
b[0] = byte(v >> 56)
|
||||
b[1] = byte(v >> 48)
|
||||
b[2] = byte(v >> 40)
|
||||
b[3] = byte(v >> 32)
|
||||
b[4] = byte(v >> 24)
|
||||
b[5] = byte(v >> 16)
|
||||
b[6] = byte(v >> 8)
|
||||
b[7] = byte(v)
|
||||
}
|
||||
|
||||
func (bigEndian) String() string { return "BigEndian" }
|
||||
|
||||
func (bigEndian) GoString() string { return "binary.BigEndian" }
|
||||
|
||||
// Read reads structured binary data from r into data.
|
||||
// Data must be a pointer to a fixed-size value or a slice
|
||||
// of fixed-size values.
|
||||
// Bytes read from r are decoded using the specified byte order
|
||||
// and written to successive fields of the data.
|
||||
// When reading into structs, the field data for fields with
|
||||
// blank (_) field names is skipped; i.e., blank field names
|
||||
// may be used for padding.
|
||||
// When reading into a struct, all non-blank fields must be exported.
|
||||
func Read(r io.Reader, order ByteOrder, data interface{}) error {
|
||||
// Fast path for basic types and slices.
|
||||
if n := intDataSize(data); n != 0 {
|
||||
var b [8]byte
|
||||
var bs []byte
|
||||
if n > len(b) {
|
||||
bs = make([]byte, n)
|
||||
} else {
|
||||
bs = b[:n]
|
||||
}
|
||||
if _, err := io.ReadFull(r, bs); err != nil {
|
||||
return err
|
||||
}
|
||||
switch data := data.(type) {
|
||||
case *int8:
|
||||
*data = int8(b[0])
|
||||
case *uint8:
|
||||
*data = b[0]
|
||||
case *int16:
|
||||
*data = int16(order.Uint16(bs))
|
||||
case *uint16:
|
||||
*data = order.Uint16(bs)
|
||||
case *int32:
|
||||
*data = int32(order.Uint32(bs))
|
||||
case *uint32:
|
||||
*data = order.Uint32(bs)
|
||||
case *int64:
|
||||
*data = int64(order.Uint64(bs))
|
||||
case *uint64:
|
||||
*data = order.Uint64(bs)
|
||||
case []int8:
|
||||
for i, x := range bs { // Easier to loop over the input for 8-bit values.
|
||||
data[i] = int8(x)
|
||||
}
|
||||
case []uint8:
|
||||
copy(data, bs)
|
||||
case []int16:
|
||||
for i := range data {
|
||||
data[i] = int16(order.Uint16(bs[2*i:]))
|
||||
}
|
||||
case []uint16:
|
||||
for i := range data {
|
||||
data[i] = order.Uint16(bs[2*i:])
|
||||
}
|
||||
case []int32:
|
||||
for i := range data {
|
||||
data[i] = int32(order.Uint32(bs[4*i:]))
|
||||
}
|
||||
case []uint32:
|
||||
for i := range data {
|
||||
data[i] = order.Uint32(bs[4*i:])
|
||||
}
|
||||
case []int64:
|
||||
for i := range data {
|
||||
data[i] = int64(order.Uint64(bs[8*i:]))
|
||||
}
|
||||
case []uint64:
|
||||
for i := range data {
|
||||
data[i] = order.Uint64(bs[8*i:])
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Fallback to reflect-based decoding.
|
||||
v := reflect.ValueOf(data)
|
||||
size := -1
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr:
|
||||
v = v.Elem()
|
||||
size = dataSize(v)
|
||||
case reflect.Slice:
|
||||
size = dataSize(v)
|
||||
}
|
||||
if size < 0 {
|
||||
return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String())
|
||||
}
|
||||
d := &decoder{order: order, buf: make([]byte, size)}
|
||||
if _, err := io.ReadFull(r, d.buf); err != nil {
|
||||
return err
|
||||
}
|
||||
d.value(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write writes the binary representation of data into w.
|
||||
// Data must be a fixed-size value or a slice of fixed-size
|
||||
// values, or a pointer to such data.
|
||||
// Bytes written to w are encoded using the specified byte order
|
||||
// and read from successive fields of the data.
|
||||
// When writing structs, zero values are written for fields
|
||||
// with blank (_) field names.
|
||||
func Write(w io.Writer, order ByteOrder, data interface{}) error {
|
||||
// Fast path for basic types and slices.
|
||||
if n := intDataSize(data); n != 0 {
|
||||
var b [8]byte
|
||||
var bs []byte
|
||||
if n > len(b) {
|
||||
bs = make([]byte, n)
|
||||
} else {
|
||||
bs = b[:n]
|
||||
}
|
||||
switch v := data.(type) {
|
||||
case *int8:
|
||||
bs = b[:1]
|
||||
b[0] = byte(*v)
|
||||
case int8:
|
||||
bs = b[:1]
|
||||
b[0] = byte(v)
|
||||
case []int8:
|
||||
for i, x := range v {
|
||||
bs[i] = byte(x)
|
||||
}
|
||||
case *uint8:
|
||||
bs = b[:1]
|
||||
b[0] = *v
|
||||
case uint8:
|
||||
bs = b[:1]
|
||||
b[0] = byte(v)
|
||||
case []uint8:
|
||||
bs = v
|
||||
case *int16:
|
||||
bs = b[:2]
|
||||
order.PutUint16(bs, uint16(*v))
|
||||
case int16:
|
||||
bs = b[:2]
|
||||
order.PutUint16(bs, uint16(v))
|
||||
case []int16:
|
||||
for i, x := range v {
|
||||
order.PutUint16(bs[2*i:], uint16(x))
|
||||
}
|
||||
case *uint16:
|
||||
bs = b[:2]
|
||||
order.PutUint16(bs, *v)
|
||||
case uint16:
|
||||
bs = b[:2]
|
||||
order.PutUint16(bs, v)
|
||||
case []uint16:
|
||||
for i, x := range v {
|
||||
order.PutUint16(bs[2*i:], x)
|
||||
}
|
||||
case *int32:
|
||||
bs = b[:4]
|
||||
order.PutUint32(bs, uint32(*v))
|
||||
case int32:
|
||||
bs = b[:4]
|
||||
order.PutUint32(bs, uint32(v))
|
||||
case []int32:
|
||||
for i, x := range v {
|
||||
order.PutUint32(bs[4*i:], uint32(x))
|
||||
}
|
||||
case *uint32:
|
||||
bs = b[:4]
|
||||
order.PutUint32(bs, *v)
|
||||
case uint32:
|
||||
bs = b[:4]
|
||||
order.PutUint32(bs, v)
|
||||
case []uint32:
|
||||
for i, x := range v {
|
||||
order.PutUint32(bs[4*i:], x)
|
||||
}
|
||||
case *int64:
|
||||
bs = b[:8]
|
||||
order.PutUint64(bs, uint64(*v))
|
||||
case int64:
|
||||
bs = b[:8]
|
||||
order.PutUint64(bs, uint64(v))
|
||||
case []int64:
|
||||
for i, x := range v {
|
||||
order.PutUint64(bs[8*i:], uint64(x))
|
||||
}
|
||||
case *uint64:
|
||||
bs = b[:8]
|
||||
order.PutUint64(bs, *v)
|
||||
case uint64:
|
||||
bs = b[:8]
|
||||
order.PutUint64(bs, v)
|
||||
case []uint64:
|
||||
for i, x := range v {
|
||||
order.PutUint64(bs[8*i:], x)
|
||||
}
|
||||
}
|
||||
_, err := w.Write(bs)
|
||||
return err
|
||||
}
|
||||
|
||||
// Fallback to reflect-based encoding.
|
||||
v := reflect.Indirect(reflect.ValueOf(data))
|
||||
size := dataSize(v)
|
||||
if size < 0 {
|
||||
return errors.New("binary.Write: invalid type " + reflect.TypeOf(data).String())
|
||||
}
|
||||
buf := make([]byte, size)
|
||||
e := &encoder{order: order, buf: buf}
|
||||
e.value(v)
|
||||
_, err := w.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// Size returns how many bytes Write would generate to encode the value v, which
|
||||
// must be a fixed-size value or a slice of fixed-size values, or a pointer to such data.
|
||||
// If v is neither of these, Size returns -1.
|
||||
func Size(v interface{}) int {
|
||||
return dataSize(reflect.Indirect(reflect.ValueOf(v)))
|
||||
}
|
||||
|
||||
// dataSize returns the number of bytes the actual data represented by v occupies in memory.
|
||||
// For compound structures, it sums the sizes of the elements. Thus, for instance, for a slice
|
||||
// it returns the length of the slice times the element size and does not count the memory
|
||||
// occupied by the header. If the type of v is not acceptable, dataSize returns -1.
|
||||
func dataSize(v reflect.Value) int {
|
||||
if v.Kind() == reflect.Slice {
|
||||
if s := sizeof(v.Type().Elem()); s >= 0 {
|
||||
return s * v.Len()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
return sizeof(v.Type())
|
||||
}
|
||||
|
||||
// sizeof returns the size >= 0 of variables for the given type or -1 if the type is not acceptable.
|
||||
func sizeof(t reflect.Type) int {
|
||||
switch t.Kind() {
|
||||
case reflect.Array:
|
||||
if s := sizeof(t.Elem()); s >= 0 {
|
||||
return s * t.Len()
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
sum := 0
|
||||
for i, n := 0, t.NumField(); i < n; i++ {
|
||||
s := sizeof(t.Field(i).Type)
|
||||
if s < 0 {
|
||||
return -1
|
||||
}
|
||||
sum += s
|
||||
}
|
||||
return sum
|
||||
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Ptr:
|
||||
return int(t.Size())
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
type coder struct {
|
||||
order ByteOrder
|
||||
buf []byte
|
||||
}
|
||||
|
||||
type decoder coder
|
||||
type encoder coder
|
||||
|
||||
func (d *decoder) uint8() uint8 {
|
||||
x := d.buf[0]
|
||||
d.buf = d.buf[1:]
|
||||
return x
|
||||
}
|
||||
|
||||
func (e *encoder) uint8(x uint8) {
|
||||
e.buf[0] = x
|
||||
e.buf = e.buf[1:]
|
||||
}
|
||||
|
||||
func (d *decoder) uint16() uint16 {
|
||||
x := d.order.Uint16(d.buf[0:2])
|
||||
d.buf = d.buf[2:]
|
||||
return x
|
||||
}
|
||||
|
||||
func (e *encoder) uint16(x uint16) {
|
||||
e.order.PutUint16(e.buf[0:2], x)
|
||||
e.buf = e.buf[2:]
|
||||
}
|
||||
|
||||
func (d *decoder) uint32() uint32 {
|
||||
x := d.order.Uint32(d.buf[0:4])
|
||||
d.buf = d.buf[4:]
|
||||
return x
|
||||
}
|
||||
|
||||
func (e *encoder) uint32(x uint32) {
|
||||
e.order.PutUint32(e.buf[0:4], x)
|
||||
e.buf = e.buf[4:]
|
||||
}
|
||||
|
||||
func (d *decoder) uint64() uint64 {
|
||||
x := d.order.Uint64(d.buf[0:8])
|
||||
d.buf = d.buf[8:]
|
||||
return x
|
||||
}
|
||||
|
||||
func (e *encoder) uint64(x uint64) {
|
||||
e.order.PutUint64(e.buf[0:8], x)
|
||||
e.buf = e.buf[8:]
|
||||
}
|
||||
|
||||
func (d *decoder) int8() int8 { return int8(d.uint8()) }
|
||||
|
||||
func (e *encoder) int8(x int8) { e.uint8(uint8(x)) }
|
||||
|
||||
func (d *decoder) int16() int16 { return int16(d.uint16()) }
|
||||
|
||||
func (e *encoder) int16(x int16) { e.uint16(uint16(x)) }
|
||||
|
||||
func (d *decoder) int32() int32 { return int32(d.uint32()) }
|
||||
|
||||
func (e *encoder) int32(x int32) { e.uint32(uint32(x)) }
|
||||
|
||||
func (d *decoder) int64() int64 { return int64(d.uint64()) }
|
||||
|
||||
func (e *encoder) int64(x int64) { e.uint64(uint64(x)) }
|
||||
|
||||
func (d *decoder) value(v reflect.Value) {
|
||||
switch v.Kind() {
|
||||
case reflect.Array:
|
||||
l := v.Len()
|
||||
for i := 0; i < l; i++ {
|
||||
d.value(v.Index(i))
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
t := v.Type()
|
||||
l := v.NumField()
|
||||
for i := 0; i < l; i++ {
|
||||
// Note: Calling v.CanSet() below is an optimization.
|
||||
// It would be sufficient to check the field name,
|
||||
// but creating the StructField info for each field is
|
||||
// costly (run "go test -bench=ReadStruct" and compare
|
||||
// results when making changes to this code).
|
||||
if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
|
||||
d.value(v)
|
||||
} else {
|
||||
d.skip(v)
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
l := v.Len()
|
||||
for i := 0; i < l; i++ {
|
||||
d.value(v.Index(i))
|
||||
}
|
||||
|
||||
case reflect.Int8:
|
||||
v.SetInt(int64(d.int8()))
|
||||
case reflect.Int16:
|
||||
v.SetInt(int64(d.int16()))
|
||||
case reflect.Int32:
|
||||
v.SetInt(int64(d.int32()))
|
||||
case reflect.Int64:
|
||||
v.SetInt(d.int64())
|
||||
|
||||
case reflect.Uint8:
|
||||
v.SetUint(uint64(d.uint8()))
|
||||
case reflect.Uint16:
|
||||
v.SetUint(uint64(d.uint16()))
|
||||
case reflect.Uint32:
|
||||
v.SetUint(uint64(d.uint32()))
|
||||
case reflect.Uint64:
|
||||
v.SetUint(d.uint64())
|
||||
|
||||
case reflect.Float32:
|
||||
v.SetFloat(float64(math.Float32frombits(d.uint32())))
|
||||
case reflect.Float64:
|
||||
v.SetFloat(math.Float64frombits(d.uint64()))
|
||||
|
||||
case reflect.Complex64:
|
||||
v.SetComplex(complex(
|
||||
float64(math.Float32frombits(d.uint32())),
|
||||
float64(math.Float32frombits(d.uint32())),
|
||||
))
|
||||
case reflect.Complex128:
|
||||
v.SetComplex(complex(
|
||||
math.Float64frombits(d.uint64()),
|
||||
math.Float64frombits(d.uint64()),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
func (e *encoder) value(v reflect.Value) {
|
||||
switch v.Kind() {
|
||||
case reflect.Array:
|
||||
l := v.Len()
|
||||
for i := 0; i < l; i++ {
|
||||
e.value(v.Index(i))
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
t := v.Type()
|
||||
l := v.NumField()
|
||||
for i := 0; i < l; i++ {
|
||||
// see comment for corresponding code in decoder.value()
|
||||
if v := v.Field(i); v.CanSet() || t.Field(i).Name != "_" {
|
||||
e.value(v)
|
||||
} else {
|
||||
e.skip(v)
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
l := v.Len()
|
||||
for i := 0; i < l; i++ {
|
||||
e.value(v.Index(i))
|
||||
}
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Int8:
|
||||
e.int8(int8(v.Int()))
|
||||
case reflect.Int16:
|
||||
e.int16(int16(v.Int()))
|
||||
case reflect.Int32:
|
||||
e.int32(int32(v.Int()))
|
||||
case reflect.Int64:
|
||||
e.int64(v.Int())
|
||||
}
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Uint8:
|
||||
e.uint8(uint8(v.Uint()))
|
||||
case reflect.Uint16:
|
||||
e.uint16(uint16(v.Uint()))
|
||||
case reflect.Uint32:
|
||||
e.uint32(uint32(v.Uint()))
|
||||
case reflect.Uint64:
|
||||
e.uint64(v.Uint())
|
||||
}
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Float32:
|
||||
e.uint32(math.Float32bits(float32(v.Float())))
|
||||
case reflect.Float64:
|
||||
e.uint64(math.Float64bits(v.Float()))
|
||||
}
|
||||
|
||||
case reflect.Complex64, reflect.Complex128:
|
||||
switch v.Type().Kind() {
|
||||
case reflect.Complex64:
|
||||
x := v.Complex()
|
||||
e.uint32(math.Float32bits(float32(real(x))))
|
||||
e.uint32(math.Float32bits(float32(imag(x))))
|
||||
case reflect.Complex128:
|
||||
x := v.Complex()
|
||||
e.uint64(math.Float64bits(real(x)))
|
||||
e.uint64(math.Float64bits(imag(x)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *decoder) skip(v reflect.Value) {
|
||||
d.buf = d.buf[dataSize(v):]
|
||||
}
|
||||
|
||||
func (e *encoder) skip(v reflect.Value) {
|
||||
n := dataSize(v)
|
||||
for i := range e.buf[0:n] {
|
||||
e.buf[i] = 0
|
||||
}
|
||||
e.buf = e.buf[n:]
|
||||
}
|
||||
|
||||
// intDataSize returns the size of the data required to represent the data when encoded.
|
||||
// It returns zero if the type cannot be implemented by the fast path in Read or Write.
|
||||
func intDataSize(data interface{}) int {
|
||||
switch data := data.(type) {
|
||||
case int8, *int8, *uint8:
|
||||
return 1
|
||||
case []int8:
|
||||
return len(data)
|
||||
case []uint8:
|
||||
return len(data)
|
||||
case int16, *int16, *uint16:
|
||||
return 2
|
||||
case []int16:
|
||||
return 2 * len(data)
|
||||
case []uint16:
|
||||
return 2 * len(data)
|
||||
case int32, *int32, *uint32:
|
||||
return 4
|
||||
case []int32:
|
||||
return 4 * len(data)
|
||||
case []uint32:
|
||||
return 4 * len(data)
|
||||
case int64, *int64, *uint64:
|
||||
return 8
|
||||
case []int64:
|
||||
return 8 * len(data)
|
||||
case []uint64:
|
||||
return 8 * len(data)
|
||||
}
|
||||
return 0
|
||||
}
|
|
@ -0,0 +1,386 @@
|
|||
package common
|
||||
|
||||
//
|
||||
// gopsutil is a port of psutil(http://pythonhosted.org/psutil/).
|
||||
// This covers these architectures.
|
||||
// - linux (amd64, arm)
|
||||
// - freebsd (amd64)
|
||||
// - windows (amd64)
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
Timeout = 3 * time.Second
|
||||
ErrTimeout = errors.New("Command timed out.")
|
||||
)
|
||||
|
||||
type Invoker interface {
|
||||
Command(string, ...string) ([]byte, error)
|
||||
}
|
||||
|
||||
type Invoke struct{}
|
||||
|
||||
func (i Invoke) Command(name string, arg ...string) ([]byte, error) {
|
||||
cmd := exec.Command(name, arg...)
|
||||
return CombinedOutputTimeout(cmd, Timeout)
|
||||
}
|
||||
|
||||
type FakeInvoke struct {
|
||||
CommandExpectedDir string // CommandExpectedDir specifies dir which includes expected outputs.
|
||||
Suffix string // Suffix species expected file name suffix such as "fail"
|
||||
Error error // If Error specfied, return the error.
|
||||
}
|
||||
|
||||
// Command in FakeInvoke returns from expected file if exists.
|
||||
func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
|
||||
if i.Error != nil {
|
||||
return []byte{}, i.Error
|
||||
}
|
||||
|
||||
arch := runtime.GOOS
|
||||
|
||||
fname := strings.Join(append([]string{name}, arg...), "")
|
||||
fname = url.QueryEscape(fname)
|
||||
var dir string
|
||||
if i.CommandExpectedDir == "" {
|
||||
dir = "expected"
|
||||
} else {
|
||||
dir = i.CommandExpectedDir
|
||||
}
|
||||
fpath := path.Join(dir, arch, fname)
|
||||
if i.Suffix != "" {
|
||||
fpath += "_" + i.Suffix
|
||||
}
|
||||
if PathExists(fpath) {
|
||||
return ioutil.ReadFile(fpath)
|
||||
}
|
||||
return exec.Command(name, arg...).Output()
|
||||
}
|
||||
|
||||
var ErrNotImplementedError = errors.New("not implemented yet")
|
||||
|
||||
// ReadLines reads contents from a file and splits them by new lines.
|
||||
// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
|
||||
func ReadLines(filename string) ([]string, error) {
|
||||
return ReadLinesOffsetN(filename, 0, -1)
|
||||
}
|
||||
|
||||
// ReadLines reads contents from file and splits them by new line.
|
||||
// The offset tells at which line number to start.
|
||||
// The count determines the number of lines to read (starting from offset):
|
||||
// n >= 0: at most n lines
|
||||
// n < 0: whole file
|
||||
func ReadLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return []string{""}, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var ret []string
|
||||
|
||||
r := bufio.NewReader(f)
|
||||
for i := 0; i < n+int(offset) || n < 0; i++ {
|
||||
line, err := r.ReadString('\n')
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if i < int(offset) {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, strings.Trim(line, "\n"))
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func IntToString(orig []int8) string {
|
||||
ret := make([]byte, len(orig))
|
||||
size := -1
|
||||
for i, o := range orig {
|
||||
if o == 0 {
|
||||
size = i
|
||||
break
|
||||
}
|
||||
ret[i] = byte(o)
|
||||
}
|
||||
if size == -1 {
|
||||
size = len(orig)
|
||||
}
|
||||
|
||||
return string(ret[0:size])
|
||||
}
|
||||
|
||||
func UintToString(orig []uint8) string {
|
||||
ret := make([]byte, len(orig))
|
||||
size := -1
|
||||
for i, o := range orig {
|
||||
if o == 0 {
|
||||
size = i
|
||||
break
|
||||
}
|
||||
ret[i] = byte(o)
|
||||
}
|
||||
if size == -1 {
|
||||
size = len(orig)
|
||||
}
|
||||
|
||||
return string(ret[0:size])
|
||||
}
|
||||
|
||||
func ByteToString(orig []byte) string {
|
||||
n := -1
|
||||
l := -1
|
||||
for i, b := range orig {
|
||||
// skip left side null
|
||||
if l == -1 && b == 0 {
|
||||
continue
|
||||
}
|
||||
if l == -1 {
|
||||
l = i
|
||||
}
|
||||
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
n = i + 1
|
||||
}
|
||||
if n == -1 {
|
||||
return string(orig)
|
||||
}
|
||||
return string(orig[l:n])
|
||||
}
|
||||
|
||||
// ReadInts reads contents from single line file and returns them as []int32.
|
||||
func ReadInts(filename string) ([]int64, error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return []int64{}, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var ret []int64
|
||||
|
||||
r := bufio.NewReader(f)
|
||||
|
||||
// The int files that this is concerned with should only be one liners.
|
||||
line, err := r.ReadString('\n')
|
||||
if err != nil {
|
||||
return []int64{}, err
|
||||
}
|
||||
|
||||
i, err := strconv.ParseInt(strings.Trim(line, "\n"), 10, 32)
|
||||
if err != nil {
|
||||
return []int64{}, err
|
||||
}
|
||||
ret = append(ret, i)
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Parse to int32 without error
|
||||
func mustParseInt32(val string) int32 {
|
||||
vv, _ := strconv.ParseInt(val, 10, 32)
|
||||
return int32(vv)
|
||||
}
|
||||
|
||||
// Parse to uint64 without error
|
||||
func mustParseUint64(val string) uint64 {
|
||||
vv, _ := strconv.ParseInt(val, 10, 64)
|
||||
return uint64(vv)
|
||||
}
|
||||
|
||||
// Parse to Float64 without error
|
||||
func mustParseFloat64(val string) float64 {
|
||||
vv, _ := strconv.ParseFloat(val, 64)
|
||||
return vv
|
||||
}
|
||||
|
||||
// StringsHas checks the target string slice contains src or not
|
||||
func StringsHas(target []string, src string) bool {
|
||||
for _, t := range target {
|
||||
if strings.TrimSpace(t) == src {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// StringsContains checks the src in any string of the target string slice
|
||||
func StringsContains(target []string, src string) bool {
|
||||
for _, t := range target {
|
||||
if strings.Contains(t, src) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IntContains checks the src in any int of the target int slice.
|
||||
func IntContains(target []int, src int) bool {
|
||||
for _, t := range target {
|
||||
if src == t {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// get struct attributes.
|
||||
// This method is used only for debugging platform dependent code.
|
||||
func attributes(m interface{}) map[string]reflect.Type {
|
||||
typ := reflect.TypeOf(m)
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
}
|
||||
|
||||
attrs := make(map[string]reflect.Type)
|
||||
if typ.Kind() != reflect.Struct {
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
p := typ.Field(i)
|
||||
if !p.Anonymous {
|
||||
attrs[p.Name] = p.Type
|
||||
}
|
||||
}
|
||||
|
||||
return attrs
|
||||
}
|
||||
|
||||
func PathExists(filename string) bool {
|
||||
if _, err := os.Stat(filename); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//GetEnv retrieves the environment variable key. If it does not exist it returns the default.
|
||||
func GetEnv(key string, dfault string, combineWith ...string) string {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
value = dfault
|
||||
}
|
||||
|
||||
switch len(combineWith) {
|
||||
case 0:
|
||||
return value
|
||||
case 1:
|
||||
return filepath.Join(value, combineWith[0])
|
||||
default:
|
||||
all := make([]string, len(combineWith)+1)
|
||||
all[0] = value
|
||||
copy(all[1:], combineWith)
|
||||
return filepath.Join(all...)
|
||||
}
|
||||
panic("invalid switch case")
|
||||
}
|
||||
|
||||
func HostProc(combineWith ...string) string {
|
||||
return GetEnv("HOST_PROC", "/proc", combineWith...)
|
||||
}
|
||||
|
||||
func HostSys(combineWith ...string) string {
|
||||
return GetEnv("HOST_SYS", "/sys", combineWith...)
|
||||
}
|
||||
|
||||
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
|
||||
if len(cmds) < 1 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
// Collect the output from the command(s)
|
||||
var output bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
|
||||
last := len(cmds) - 1
|
||||
for i, cmd := range cmds[:last] {
|
||||
var err error
|
||||
// Connect each command's stdin to the previous command's stdout
|
||||
if cmds[i+1].Stdin, err = cmd.StdoutPipe(); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Connect each command's stderr to a buffer
|
||||
cmd.Stderr = &stderr
|
||||
}
|
||||
|
||||
// Connect the output and error for the last command
|
||||
cmds[last].Stdout, cmds[last].Stderr = &output, &stderr
|
||||
|
||||
// Start each command
|
||||
for _, cmd := range cmds {
|
||||
if err := cmd.Start(); err != nil {
|
||||
return output.Bytes(), stderr.Bytes(), err
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for each command to complete
|
||||
for _, cmd := range cmds {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return output.Bytes(), stderr.Bytes(), err
|
||||
}
|
||||
}
|
||||
|
||||
// Return the pipeline output and the collected standard error
|
||||
return output.Bytes(), stderr.Bytes(), nil
|
||||
}
|
70
vendor/github.com/shirou/gopsutil/internal/common/common_darwin.go
generated
vendored
Normal file
70
vendor/github.com/shirou/gopsutil/internal/common/common_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
// +build darwin
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func DoSysctrl(mib string) ([]string, error) {
|
||||
err := os.Setenv("LC_ALL", "C")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
|
||||
sysctl, err := exec.LookPath("/usr/sbin/sysctl")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
out, err := exec.Command(sysctl, "-n", mib).Output()
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
v := strings.Replace(string(out), "{ ", "", 1)
|
||||
v = strings.Replace(string(v), " }", "", 1)
|
||||
values := strings.Fields(string(v))
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func CallSyscall(mib []int32) ([]byte, uint64, error) {
|
||||
miblen := uint64(len(mib))
|
||||
|
||||
// get required buffer size
|
||||
length := uint64(0)
|
||||
_, _, err := syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(unsafe.Pointer(&mib[0])),
|
||||
uintptr(miblen),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&length)),
|
||||
0,
|
||||
0)
|
||||
if err != 0 {
|
||||
var b []byte
|
||||
return b, length, err
|
||||
}
|
||||
if length == 0 {
|
||||
var b []byte
|
||||
return b, length, err
|
||||
}
|
||||
// get proc info itself
|
||||
buf := make([]byte, length)
|
||||
_, _, err = syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(unsafe.Pointer(&mib[0])),
|
||||
uintptr(miblen),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(&length)),
|
||||
0,
|
||||
0)
|
||||
if err != 0 {
|
||||
return buf, length, err
|
||||
}
|
||||
|
||||
return buf, length, nil
|
||||
}
|
70
vendor/github.com/shirou/gopsutil/internal/common/common_freebsd.go
generated
vendored
Normal file
70
vendor/github.com/shirou/gopsutil/internal/common/common_freebsd.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
// +build freebsd openbsd
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func DoSysctrl(mib string) ([]string, error) {
|
||||
err := os.Setenv("LC_ALL", "C")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
sysctl, err := exec.LookPath("/sbin/sysctl")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
out, err := exec.Command(sysctl, "-n", mib).Output()
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
v := strings.Replace(string(out), "{ ", "", 1)
|
||||
v = strings.Replace(string(v), " }", "", 1)
|
||||
values := strings.Fields(string(v))
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func CallSyscall(mib []int32) ([]byte, uint64, error) {
|
||||
mibptr := unsafe.Pointer(&mib[0])
|
||||
miblen := uint64(len(mib))
|
||||
|
||||
// get required buffer size
|
||||
length := uint64(0)
|
||||
_, _, err := syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(mibptr),
|
||||
uintptr(miblen),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&length)),
|
||||
0,
|
||||
0)
|
||||
if err != 0 {
|
||||
var b []byte
|
||||
return b, length, err
|
||||
}
|
||||
if length == 0 {
|
||||
var b []byte
|
||||
return b, length, err
|
||||
}
|
||||
// get proc info itself
|
||||
buf := make([]byte, length)
|
||||
_, _, err = syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(mibptr),
|
||||
uintptr(miblen),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(&length)),
|
||||
0,
|
||||
0)
|
||||
if err != 0 {
|
||||
return buf, length, err
|
||||
}
|
||||
|
||||
return buf, length, nil
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// +build linux
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func DoSysctrl(mib string) ([]string, error) {
|
||||
err := os.Setenv("LC_ALL", "C")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
sysctl, err := exec.LookPath("/sbin/sysctl")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
out, err := exec.Command(sysctl, "-n", mib).Output()
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
v := strings.Replace(string(out), "{ ", "", 1)
|
||||
v = strings.Replace(string(v), " }", "", 1)
|
||||
values := strings.Fields(string(v))
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func NumProcs() (uint64, error) {
|
||||
f, err := os.Open(HostProc())
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
list, err := f.Readdir(-1)
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint64(len(list)), err
|
||||
}
|
70
vendor/github.com/shirou/gopsutil/internal/common/common_openbsd.go
generated
vendored
Normal file
70
vendor/github.com/shirou/gopsutil/internal/common/common_openbsd.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
// +build openbsd
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func DoSysctrl(mib string) ([]string, error) {
|
||||
err := os.Setenv("LC_ALL", "C")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
sysctl, err := exec.LookPath("/sbin/sysctl")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
out, err := exec.Command(sysctl, "-n", mib).Output()
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
v := strings.Replace(string(out), "{ ", "", 1)
|
||||
v = strings.Replace(string(v), " }", "", 1)
|
||||
values := strings.Fields(string(v))
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func CallSyscall(mib []int32) ([]byte, uint64, error) {
|
||||
mibptr := unsafe.Pointer(&mib[0])
|
||||
miblen := uint64(len(mib))
|
||||
|
||||
// get required buffer size
|
||||
length := uint64(0)
|
||||
_, _, err := syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(mibptr),
|
||||
uintptr(miblen),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&length)),
|
||||
0,
|
||||
0)
|
||||
if err != 0 {
|
||||
var b []byte
|
||||
return b, length, err
|
||||
}
|
||||
if length == 0 {
|
||||
var b []byte
|
||||
return b, length, err
|
||||
}
|
||||
// get proc info itself
|
||||
buf := make([]byte, length)
|
||||
_, _, err = syscall.Syscall6(
|
||||
syscall.SYS___SYSCTL,
|
||||
uintptr(mibptr),
|
||||
uintptr(miblen),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(&length)),
|
||||
0,
|
||||
0)
|
||||
if err != 0 {
|
||||
return buf, length, err
|
||||
}
|
||||
|
||||
return buf, length, nil
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
// +build linux freebsd darwin openbsd
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CallLsof(invoke Invoker, pid int32, args ...string) ([]string, error) {
|
||||
var cmd []string
|
||||
if pid == 0 { // will get from all processes.
|
||||
cmd = []string{"-a", "-n", "-P"}
|
||||
} else {
|
||||
cmd = []string{"-a", "-n", "-P", "-p", strconv.Itoa(int(pid))}
|
||||
}
|
||||
cmd = append(cmd, args...)
|
||||
lsof, err := exec.LookPath("lsof")
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
out, err := invoke.Command(lsof, cmd...)
|
||||
if err != nil {
|
||||
// if no pid found, lsof returnes code 1.
|
||||
if err.Error() == "exit status 1" && len(out) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
|
||||
var ret []string
|
||||
for _, l := range lines[1:] {
|
||||
if len(l) == 0 {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, l)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func CallPgrep(invoke Invoker, pid int32) ([]int32, error) {
|
||||
var cmd []string
|
||||
cmd = []string{"-P", strconv.Itoa(int(pid))}
|
||||
pgrep, err := exec.LookPath("pgrep")
|
||||
if err != nil {
|
||||
return []int32{}, err
|
||||
}
|
||||
out, err := invoke.Command(pgrep, cmd...)
|
||||
if err != nil {
|
||||
return []int32{}, err
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
ret := make([]int32, 0, len(lines))
|
||||
for _, l := range lines {
|
||||
if len(l) == 0 {
|
||||
continue
|
||||
}
|
||||
i, err := strconv.Atoi(l)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, int32(i))
|
||||
}
|
||||
return ret, nil
|
||||
}
|
110
vendor/github.com/shirou/gopsutil/internal/common/common_windows.go
generated
vendored
Normal file
110
vendor/github.com/shirou/gopsutil/internal/common/common_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
// +build windows
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// for double values
|
||||
type PDH_FMT_COUNTERVALUE_DOUBLE struct {
|
||||
CStatus uint32
|
||||
DoubleValue float64
|
||||
}
|
||||
|
||||
// for 64 bit integer values
|
||||
type PDH_FMT_COUNTERVALUE_LARGE struct {
|
||||
CStatus uint32
|
||||
LargeValue int64
|
||||
}
|
||||
|
||||
// for long values
|
||||
type PDH_FMT_COUNTERVALUE_LONG struct {
|
||||
CStatus uint32
|
||||
LongValue int32
|
||||
padding [4]byte
|
||||
}
|
||||
|
||||
// windows system const
|
||||
const (
|
||||
ERROR_SUCCESS = 0
|
||||
ERROR_FILE_NOT_FOUND = 2
|
||||
DRIVE_REMOVABLE = 2
|
||||
DRIVE_FIXED = 3
|
||||
HKEY_LOCAL_MACHINE = 0x80000002
|
||||
RRF_RT_REG_SZ = 0x00000002
|
||||
RRF_RT_REG_DWORD = 0x00000010
|
||||
PDH_FMT_LONG = 0x00000100
|
||||
PDH_FMT_DOUBLE = 0x00000200
|
||||
PDH_FMT_LARGE = 0x00000400
|
||||
PDH_INVALID_DATA = 0xc0000bc6
|
||||
PDH_INVALID_HANDLE = 0xC0000bbc
|
||||
PDH_NO_DATA = 0x800007d5
|
||||
)
|
||||
|
||||
var (
|
||||
Modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
ModNt = syscall.NewLazyDLL("ntdll.dll")
|
||||
ModPdh = syscall.NewLazyDLL("pdh.dll")
|
||||
|
||||
ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes")
|
||||
ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation")
|
||||
PdhOpenQuery = ModPdh.NewProc("PdhOpenQuery")
|
||||
PdhAddCounter = ModPdh.NewProc("PdhAddCounterW")
|
||||
PdhCollectQueryData = ModPdh.NewProc("PdhCollectQueryData")
|
||||
PdhGetFormattedCounterValue = ModPdh.NewProc("PdhGetFormattedCounterValue")
|
||||
PdhCloseQuery = ModPdh.NewProc("PdhCloseQuery")
|
||||
)
|
||||
|
||||
type FILETIME struct {
|
||||
DwLowDateTime uint32
|
||||
DwHighDateTime uint32
|
||||
}
|
||||
|
||||
// borrowed from net/interface_windows.go
|
||||
func BytePtrToString(p *uint8) string {
|
||||
a := (*[10000]uint8)(unsafe.Pointer(p))
|
||||
i := 0
|
||||
for a[i] != 0 {
|
||||
i++
|
||||
}
|
||||
return string(a[:i])
|
||||
}
|
||||
|
||||
// CounterInfo
|
||||
// copied from https://github.com/mackerelio/mackerel-agent/
|
||||
type CounterInfo struct {
|
||||
PostName string
|
||||
CounterName string
|
||||
Counter syscall.Handle
|
||||
}
|
||||
|
||||
// CreateQuery XXX
|
||||
// copied from https://github.com/mackerelio/mackerel-agent/
|
||||
func CreateQuery() (syscall.Handle, error) {
|
||||
var query syscall.Handle
|
||||
r, _, err := PdhOpenQuery.Call(0, 0, uintptr(unsafe.Pointer(&query)))
|
||||
if r != 0 {
|
||||
return 0, err
|
||||
}
|
||||
return query, nil
|
||||
}
|
||||
|
||||
// CreateCounter XXX
|
||||
func CreateCounter(query syscall.Handle, pname, cname string) (*CounterInfo, error) {
|
||||
var counter syscall.Handle
|
||||
r, _, err := PdhAddCounter.Call(
|
||||
uintptr(query),
|
||||
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(cname))),
|
||||
0,
|
||||
uintptr(unsafe.Pointer(&counter)))
|
||||
if r != 0 {
|
||||
return nil, err
|
||||
}
|
||||
return &CounterInfo{
|
||||
PostName: pname,
|
||||
CounterName: cname,
|
||||
Counter: counter,
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
DIRS="cpu disk docker host load mem net process"
|
||||
|
||||
GOOS=`uname | tr '[:upper:]' '[:lower:]'`
|
||||
ARCH=`uname -m`
|
||||
|
||||
case $ARCH in
|
||||
amd64)
|
||||
GOARCH="amd64"
|
||||
;;
|
||||
x86_64)
|
||||
GOARCH="amd64"
|
||||
;;
|
||||
i386)
|
||||
GOARCH="386"
|
||||
;;
|
||||
i686)
|
||||
GOARCH="386"
|
||||
;;
|
||||
arm)
|
||||
GOARCH="arm"
|
||||
;;
|
||||
*)
|
||||
echo "unknown arch: $ARCH"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
for DIR in $DIRS
|
||||
do
|
||||
if [ -e ${DIR}/types_${GOOS}.go ]; then
|
||||
echo "// +build $GOOS" > ${DIR}/${DIR}_${GOOS}_${GOARCH}.go
|
||||
echo "// +build $GOARCH" >> ${DIR}/${DIR}_${GOOS}_${GOARCH}.go
|
||||
go tool cgo -godefs ${DIR}/types_${GOOS}.go >> ${DIR}/${DIR}_${GOOS}_${GOARCH}.go
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
# This script is a helper of migration to gopsutil v2 using gorename
|
||||
#
|
||||
# go get golang.org/x/tools/cmd/gorename
|
||||
|
||||
IFS=$'\n'
|
||||
|
||||
## Part 1. rename Functions to pass golint. ex) cpu.CPUTimesStat -> cpu.TimesStat
|
||||
|
||||
#
|
||||
# Note:
|
||||
# process has IOCounters() for file IO, and also NetIOCounters() for Net IO.
|
||||
# This scripts replace process.NetIOCounters() to IOCounters().
|
||||
# So you need hand-fixing process.
|
||||
|
||||
TARGETS=`cat <<EOF
|
||||
CPUTimesStat -> TimesStat
|
||||
CPUInfoStat -> InfoStat
|
||||
CPUTimes -> Times
|
||||
CPUInfo -> Info
|
||||
CPUCounts -> Counts
|
||||
CPUPercent -> Percent
|
||||
DiskUsageStat -> UsageStat
|
||||
DiskPartitionStat -> PartitionStat
|
||||
DiskIOCountersStat -> IOCountersStat
|
||||
DiskPartitions -> Partitions
|
||||
DiskIOCounters -> IOCounters
|
||||
DiskUsage -> Usage
|
||||
HostInfoStat -> InfoStat
|
||||
HostInfo -> Info
|
||||
GetVirtualization -> Virtualization
|
||||
GetPlatformInformation -> PlatformInformation
|
||||
LoadAvgStat -> AvgStat
|
||||
LoadAvg -> Avg
|
||||
NetIOCountersStat -> IOCountersStat
|
||||
NetConnectionStat -> ConnectionStat
|
||||
NetProtoCountersStat -> ProtoCountersStat
|
||||
NetInterfaceAddr -> InterfaceAddr
|
||||
NetInterfaceStat -> InterfaceStat
|
||||
NetFilterStat -> FilterStat
|
||||
NetInterfaces -> Interfaces
|
||||
getNetIOCountersAll -> getIOCountersAll
|
||||
NetIOCounters -> IOCounters
|
||||
NetIOCountersByFile -> IOCountersByFile
|
||||
NetProtoCounters -> ProtoCounters
|
||||
NetFilterCounters -> FilterCounters
|
||||
NetConnections -> Connections
|
||||
NetConnectionsPid -> ConnectionsPid
|
||||
Uid -> UID
|
||||
Id -> ID
|
||||
convertCpuTimes -> convertCPUTimes
|
||||
EOF`
|
||||
|
||||
for T in $TARGETS
|
||||
do
|
||||
echo $T
|
||||
gofmt -w -r "$T" ./*.go
|
||||
done
|
||||
|
||||
|
||||
###### Part 2 rename JSON key name
|
||||
## Google JSOn style
|
||||
## https://google.github.io/styleguide/jsoncstyleguide.xml
|
||||
|
||||
sed -i "" 's/guest_nice/guestNice/g' cpu/*.go
|
||||
sed -i "" 's/vendor_id/vendorId/g' cpu/*.go
|
||||
sed -i "" 's/physical_id/physicalId/g' cpu/*.go
|
||||
sed -i "" 's/model_name/modelName/g' cpu/*.go
|
||||
sed -i "" 's/cache_size/cacheSize/g' cpu/*.go
|
||||
sed -i "" 's/core_id/coreId/g' cpu/*.go
|
||||
|
||||
sed -i "" 's/inodes_total/inodesTotal/g' disk/*.go
|
||||
sed -i "" 's/inodes_used/inodesUsed/g' disk/*.go
|
||||
sed -i "" 's/inodes_free/inodesFree/g' disk/*.go
|
||||
sed -i "" 's/inodes_used_percent/inodesUsedPercent/g' disk/*.go
|
||||
sed -i "" 's/read_count/readCount/g' disk/*.go
|
||||
sed -i "" 's/write_count/writeCount/g' disk/*.go
|
||||
sed -i "" 's/read_bytes/readBytes/g' disk/*.go
|
||||
sed -i "" 's/write_bytes/writeBytes/g' disk/*.go
|
||||
sed -i "" 's/read_time/readTime/g' disk/*.go
|
||||
sed -i "" 's/write_time/writeTime/g' disk/*.go
|
||||
sed -i "" 's/io_time/ioTime/g' disk/*.go
|
||||
sed -i "" 's/serial_number/serialNumber/g' disk/*.go
|
||||
sed -i "" 's/used_percent/usedPercent/g' disk/*.go
|
||||
sed -i "" 's/inodesUsed_percent/inodesUsedPercent/g' disk/*.go
|
||||
|
||||
sed -i "" 's/total_cache/totalCache/g' docker/*.go
|
||||
sed -i "" 's/total_rss_huge/totalRssHuge/g' docker/*.go
|
||||
sed -i "" 's/total_rss/totalRss/g' docker/*.go
|
||||
sed -i "" 's/total_mapped_file/totalMappedFile/g' docker/*.go
|
||||
sed -i "" 's/total_pgpgin/totalPgpgin/g' docker/*.go
|
||||
sed -i "" 's/total_pgpgout/totalPgpgout/g' docker/*.go
|
||||
sed -i "" 's/total_pgfault/totalPgfault/g' docker/*.go
|
||||
sed -i "" 's/total_pgmajfault/totalPgmajfault/g' docker/*.go
|
||||
sed -i "" 's/total_inactive_anon/totalInactiveAnon/g' docker/*.go
|
||||
sed -i "" 's/total_active_anon/totalActiveAnon/g' docker/*.go
|
||||
sed -i "" 's/total_inactive_file/totalInactiveFile/g' docker/*.go
|
||||
sed -i "" 's/total_active_file/totalActiveFile/g' docker/*.go
|
||||
sed -i "" 's/total_unevictable/totalUnevictable/g' docker/*.go
|
||||
sed -i "" 's/mem_usage_in_bytes/memUsageInBytes/g' docker/*.go
|
||||
sed -i "" 's/mem_max_usage_in_bytes/memMaxUsageInBytes/g' docker/*.go
|
||||
sed -i "" 's/memory.limit_in_bytes/memoryLimitInBbytes/g' docker/*.go
|
||||
sed -i "" 's/memory.failcnt/memoryFailcnt/g' docker/*.go
|
||||
sed -i "" 's/mapped_file/mappedFile/g' docker/*.go
|
||||
sed -i "" 's/container_id/containerID/g' docker/*.go
|
||||
sed -i "" 's/rss_huge/rssHuge/g' docker/*.go
|
||||
sed -i "" 's/inactive_anon/inactiveAnon/g' docker/*.go
|
||||
sed -i "" 's/active_anon/activeAnon/g' docker/*.go
|
||||
sed -i "" 's/inactive_file/inactiveFile/g' docker/*.go
|
||||
sed -i "" 's/active_file/activeFile/g' docker/*.go
|
||||
sed -i "" 's/hierarchical_memory_limit/hierarchicalMemoryLimit/g' docker/*.go
|
||||
|
||||
sed -i "" 's/boot_time/bootTime/g' host/*.go
|
||||
sed -i "" 's/platform_family/platformFamily/g' host/*.go
|
||||
sed -i "" 's/platform_version/platformVersion/g' host/*.go
|
||||
sed -i "" 's/virtualization_system/virtualizationSystem/g' host/*.go
|
||||
sed -i "" 's/virtualization_role/virtualizationRole/g' host/*.go
|
||||
|
||||
sed -i "" 's/used_percent/usedPercent/g' mem/*.go
|
||||
|
||||
sed -i "" 's/bytes_sent/bytesSent/g' net/*.go
|
||||
sed -i "" 's/bytes_recv/bytesRecv/g' net/*.go
|
||||
sed -i "" 's/packets_sent/packetsSent/g' net/*.go
|
||||
sed -i "" 's/packets_recv/packetsRecv/g' net/*.go
|
||||
sed -i "" 's/conntrack_count/conntrackCount/g' net/*.go
|
||||
sed -i "" 's/conntrack_max/conntrackMax/g' net/*.go
|
||||
|
||||
sed -i "" 's/read_count/readCount/g' process/*.go
|
||||
sed -i "" 's/write_count/writeCount/g' process/*.go
|
||||
sed -i "" 's/read_bytes/readBytes/g' process/*.go
|
||||
sed -i "" 's/write_bytes/writeBytes/g' process/*.go
|
||||
sed -i "" 's/shared_clean/sharedClean/g' process/*.go
|
||||
sed -i "" 's/shared_dirty/sharedDirty/g' process/*.go
|
||||
sed -i "" 's/private_clean/privateClean/g' process/*.go
|
||||
sed -i "" 's/private_dirty/privateDirty/g' process/*.go
|
|
@ -0,0 +1,36 @@
|
|||
Windows memo
|
||||
=====================
|
||||
|
||||
Size
|
||||
----------
|
||||
|
||||
DWORD
|
||||
32-bit unsigned integer
|
||||
DWORDLONG
|
||||
64-bit unsigned integer
|
||||
DWORD_PTR
|
||||
unsigned long type for pointer precision
|
||||
DWORD32
|
||||
32-bit unsigned integer
|
||||
DWORD64
|
||||
64-bit unsigned integer
|
||||
HALF_PTR
|
||||
_WIN64 = int, else short
|
||||
INT
|
||||
32-bit signed integer
|
||||
INT_PTR
|
||||
_WIN64 = __int64 else int
|
||||
LONG
|
||||
32-bit signed integer
|
||||
LONGLONG
|
||||
64-bit signed integer
|
||||
LONG_PTR
|
||||
_WIN64 = __int64 else long
|
||||
SHORT
|
||||
16-bit integer
|
||||
SIZE_T
|
||||
maximum number of bytes to which a pointer can point. typedef ULONG_PTR SIZE_T;
|
||||
SSIZE_T
|
||||
signed version of SIZE_T. typedef LONG_PTR SSIZE_T;
|
||||
WORD
|
||||
16-bit unsigned integer
|
|
@ -674,6 +674,24 @@
|
|||
"revision": "9b3edd62028f107d7cabb19353292afd29311a4e",
|
||||
"revisionTime": "2016-07-12T16:32:29Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "HoB8jOyjbTgm03BTbwkwqH+lrXs=",
|
||||
"path": "github.com/shirou/gopsutil",
|
||||
"revision": "70a1b78fe69202d93d6718fc9e3a4d6f81edfd58",
|
||||
"revisionTime": "2017-01-30T15:34:44Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "74PIzS+la5td63oGs74K66mQ7hk=",
|
||||
"path": "github.com/shirou/gopsutil/host",
|
||||
"revision": "70a1b78fe69202d93d6718fc9e3a4d6f81edfd58",
|
||||
"revisionTime": "2017-01-30T15:34:44Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "F4xYQ60JlmamCUSCJl7zuuq58Kw=",
|
||||
"path": "github.com/shirou/gopsutil/internal/common",
|
||||
"revision": "70a1b78fe69202d93d6718fc9e3a4d6f81edfd58",
|
||||
"revisionTime": "2017-01-30T15:34:44Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=",
|
||||
"path": "golang.org/x/net/context",
|
||||
|
|
Loading…
Reference in New Issue