godep update for procstat

This commit is contained in:
Cameron Sparr 2015-10-05 11:14:13 -06:00
parent fdf00c1be6
commit 5cc26bb640
34 changed files with 4820 additions and 1 deletions

10
Godeps/Godeps.json generated
View File

@ -195,6 +195,11 @@
"Comment": "1.0.0-161-g3303647", "Comment": "1.0.0-161-g3303647",
"Rev": "3303647209557312e5db51450ea8bbdef56d5176" "Rev": "3303647209557312e5db51450ea8bbdef56d5176"
}, },
{
"ImportPath": "github.com/shirou/gopsutil/host",
"Comment": "1.0.0-153-gc1313e7",
"Rev": "c1313e76341b18456212c5645d1daa7f132ac50e"
},
{ {
"ImportPath": "github.com/shirou/gopsutil/load", "ImportPath": "github.com/shirou/gopsutil/load",
"Comment": "1.0.0-161-g3303647", "Comment": "1.0.0-161-g3303647",
@ -210,6 +215,11 @@
"Comment": "1.0.0-161-g3303647", "Comment": "1.0.0-161-g3303647",
"Rev": "3303647209557312e5db51450ea8bbdef56d5176" "Rev": "3303647209557312e5db51450ea8bbdef56d5176"
}, },
{
"ImportPath": "github.com/shirou/gopsutil/process",
"Comment": "1.0.0-153-gc1313e7",
"Rev": "c1313e76341b18456212c5645d1daa7f132ac50e"
},
{ {
"ImportPath": "github.com/streadway/amqp", "ImportPath": "github.com/streadway/amqp",
"Rev": "f4879ba28fffbb576743b03622a9ff20461826b2" "Rev": "f4879ba28fffbb576743b03622a9ff20461826b2"

View File

@ -0,0 +1,37 @@
package host
import (
"encoding/json"
)
// A HostInfoStat describes the host status.
// This is not in the psutil but it useful.
type HostInfoStat struct {
Hostname string `json:"hostname"`
Uptime uint64 `json:"uptime"`
Procs uint64 `json:"procs"` // number of processes
OS string `json:"os"` // ex: freebsd, linux
Platform string `json:"platform"` // ex: ubuntu, linuxmint
PlatformFamily string `json:"platform_family"` // ex: debian, rhel
PlatformVersion string `json:"platform_version"`
VirtualizationSystem string `json:"virtualization_system"`
VirtualizationRole string `json:"virtualization_role"` // guest or host
}
type UserStat struct {
User string `json:"user"`
Terminal string `json:"terminal"`
Host string `json:"host"`
Started int `json:"started"`
}
func (h HostInfoStat) String() string {
s, _ := json.Marshal(h)
return string(s)
}
func (u UserStat) String() string {
s, _ := json.Marshal(u)
return string(s)
}

View File

@ -0,0 +1,139 @@
// +build darwin
package host
import (
"bytes"
"encoding/binary"
"io/ioutil"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"unsafe"
common "github.com/shirou/gopsutil/common"
)
func HostInfo() (*HostInfoStat, error) {
ret := &HostInfoStat{
OS: runtime.GOOS,
PlatformFamily: "darwin",
}
hostname, err := os.Hostname()
if err != nil {
return ret, err
}
ret.Hostname = hostname
platform, family, version, err := GetPlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
}
system, role, err := GetVirtualization()
if err == nil {
ret.VirtualizationSystem = system
ret.VirtualizationRole = role
}
values, err := common.DoSysctrl("kern.boottime")
if err == nil {
// ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014
v := strings.Replace(values[2], ",", "", 1)
t, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return ret, err
}
ret.Uptime = t
}
return ret, nil
}
func BootTime() (uint64, error) {
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
}
return uint64(boottime), 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 != 7 { // skip if not USERPROCESS
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 GetPlatformInformation() (string, string, string, error) {
platform := ""
family := ""
version := ""
out, err := exec.Command("uname", "-s").Output()
if err == nil {
platform = strings.ToLower(strings.TrimSpace(string(out)))
}
out, err = exec.Command("uname", "-r").Output()
if err == nil {
version = strings.ToLower(strings.TrimSpace(string(out)))
}
return platform, family, version, nil
}
func GetVirtualization() (string, string, error) {
system := ""
role := ""
return system, role, nil
}

View File

@ -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
}

View File

@ -0,0 +1,185 @@
// +build freebsd
package host
import (
"bytes"
"encoding/binary"
"io/ioutil"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"unsafe"
common "github.com/shirou/gopsutil/common"
)
const (
UTNameSize = 16 /* see MAXLOGNAME in <sys/param.h> */
UTLineSize = 8
UTHostSize = 16
)
func HostInfo() (*HostInfoStat, error) {
ret := &HostInfoStat{
OS: runtime.GOOS,
PlatformFamily: "freebsd",
}
hostname, err := os.Hostname()
if err != nil {
return ret, err
}
ret.Hostname = hostname
platform, family, version, err := GetPlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
}
system, role, err := GetVirtualization()
if err == nil {
ret.VirtualizationSystem = system
ret.VirtualizationRole = role
}
values, err := common.DoSysctrl("kern.boottime")
if err == nil {
// ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014
v := strings.Replace(values[2], ",", "", 1)
t, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return ret, err
}
ret.Uptime = t
}
return ret, nil
}
func BootTime() (int64, error) {
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
}
return boottime, 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
}
u := Utmpx{}
entrySize := int(unsafe.Sizeof(u)) - 3
entrySize = 197 // TODO: why should 197
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 || 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 GetPlatformInformation() (string, string, string, error) {
platform := ""
family := ""
version := ""
out, err := exec.Command("uname", "-s").Output()
if err == nil {
platform = strings.ToLower(strings.TrimSpace(string(out)))
}
out, err = exec.Command("uname", "-r").Output()
if err == nil {
version = strings.ToLower(strings.TrimSpace(string(out)))
}
return platform, family, version, nil
}
func GetVirtualization() (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
}

View File

@ -0,0 +1,41 @@
// 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
)
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
}

View File

@ -0,0 +1,402 @@
// +build linux
package host
import (
"bytes"
"encoding/binary"
"fmt"
"io/ioutil"
"os"
"os/exec"
"regexp"
"runtime"
"strconv"
"strings"
"unsafe"
common "github.com/shirou/gopsutil/common"
)
type LSB struct {
ID string
Release string
Codename string
Description string
}
func HostInfo() (*HostInfoStat, error) {
hostname, err := os.Hostname()
if err != nil {
return nil, err
}
ret := &HostInfoStat{
Hostname: hostname,
OS: runtime.GOOS,
}
platform, family, version, err := GetPlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
}
system, role, err := GetVirtualization()
if err == nil {
ret.VirtualizationSystem = system
ret.VirtualizationRole = role
}
uptime, err := BootTime()
if err == nil {
ret.Uptime = uptime
}
return ret, nil
}
// BootTime returns the system boot time expressed in seconds since the epoch.
func BootTime() (uint64, error) {
lines, err := common.ReadLines("/proc/stat")
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
}
return uint64(b), nil
}
}
return 0, fmt.Errorf("could not find btime")
}
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
}
u := utmp{}
entrySize := int(unsafe.Sizeof(u))
count := len(buf) / entrySize
ret := make([]UserStat, 0, count)
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 {
continue
}
user := UserStat{
User: common.IntToString(u.User[:]),
Terminal: common.IntToString(u.Line[:]),
Host: common.IntToString(u.Host[:]),
Started: int(u.Tv.TvSec),
}
ret = append(ret, user)
}
return ret, nil
}
func getLSB() (*LSB, error) {
ret := &LSB{}
if common.PathExists("/etc/lsb-release") {
contents, err := common.ReadLines("/etc/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") {
out, err := exec.Command("/usr/bin/lsb_release").Output()
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 GetPlatformInformation() (platform string, family string, version string, err error) {
lsb, err := getLSB()
if err != nil {
lsb = &LSB{}
}
if common.PathExists("/etc/oracle-release") {
platform = "oracle"
contents, err := common.ReadLines("/etc/oracle-release")
if err == nil {
version = getRedhatishVersion(contents)
}
} else if common.PathExists("/etc/enterprise-release") {
platform = "oracle"
contents, err := common.ReadLines("/etc/enterprise-release")
if err == nil {
version = getRedhatishVersion(contents)
}
} else if common.PathExists("/etc/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("/etc/debian_version")
if err == nil {
version = contents[0]
}
}
} else if common.PathExists("/etc/redhat-release") {
contents, err := common.ReadLines("/etc/redhat-release")
if err == nil {
version = getRedhatishVersion(contents)
platform = getRedhatishPlatform(contents)
}
} else if common.PathExists("/etc/system-release") {
contents, err := common.ReadLines("/etc/system-release")
if err == nil {
version = getRedhatishVersion(contents)
platform = getRedhatishPlatform(contents)
}
} else if common.PathExists("/etc/gentoo-release") {
platform = "gentoo"
contents, err := common.ReadLines("/etc/gentoo-release")
if err == nil {
version = getRedhatishVersion(contents)
}
} else if common.PathExists("/etc/SuSE-release") {
contents, err := common.ReadLines("/etc/SuSE-release")
if err == nil {
version = getSuseVersion(contents)
platform = getSusePlatform(contents)
}
// TODO: slackware detecion
} else if common.PathExists("/etc/arch-release") {
platform = "arch"
// TODO: exherbo detection
} 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"
}
return platform, family, 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 GetVirtualization() (string, string, error) {
var system string
var role string
if common.PathExists("/proc/xen") {
system = "xen"
role = "guest" // assume guest
if common.PathExists("/proc/xen/capabilities") {
contents, err := common.ReadLines("/proc/xen/capabilities")
if err == nil {
if common.StringsHas(contents, "control_d") {
role = "host"
}
}
}
}
if common.PathExists("/proc/modules") {
contents, err := common.ReadLines("/proc/modules")
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"
}
}
}
if common.PathExists("/proc/cpuinfo") {
contents, err := common.ReadLines("/proc/cpuinfo")
if err == nil {
if common.StringsHas(contents, "QEMU Virtual CPU") ||
common.StringsHas(contents, "Common KVM processor") ||
common.StringsHas(contents, "Common 32-bit KVM processor") {
system = "kvm"
role = "guest"
}
}
}
if common.PathExists("/proc/bc/0") {
system = "openvz"
role = "host"
} else if common.PathExists("/proc/vz") {
system = "openvz"
role = "guest"
}
// not use dmidecode because it requires root
if common.PathExists("/proc/self/status") {
contents, err := common.ReadLines("/proc/self/status")
if err == nil {
if common.StringsHas(contents, "s_context:") ||
common.StringsHas(contents, "VxID:") {
system = "linux-vserver"
}
// TODO: guest or host
}
}
if common.PathExists("/proc/self/cgroup") {
contents, err := common.ReadLines("/proc/self/cgroup")
if err == nil {
if common.StringsHas(contents, "lxc") ||
common.StringsHas(contents, "docker") {
system = "lxc"
role = "guest"
} else if common.PathExists("/usr/bin/lxc-version") { // TODO: which
system = "lxc"
role = "host"
}
}
}
return system, role, nil
}

View File

@ -0,0 +1,44 @@
// 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
)
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 {
TvSec int32
TvUsec int32
}

View File

@ -0,0 +1,42 @@
// 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
)
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 UtTv
Addr_v6 [4]int32
X__glibc_reserved [20]int8
}
type exit_status struct {
Termination int16
Exit int16
}
type UtTv struct {
TvSec int32
TvUsec int32
}

View File

@ -0,0 +1,27 @@
// +build linux
// +build arm
package host
type exitStatus struct {
Etermination int16 // Process termination status.
Eexit int16 // Process exit status.
}
type timeval struct {
TvSec uint32 // Seconds.
TvUsec uint32 // Microseconds.
}
type utmp struct {
Type int16 // Type of login.
Pid int32 // Process ID of login process.
Line [32]byte // Devicename.
ID [4]byte // Inittab ID.
User [32]byte // Username.
Host [256]byte // Hostname for remote login.
Exit exitStatus // Exit status of a process marked
Session int32 // Session ID, used for windowing.
Tv timeval // Time entry was made.
AddrV6 [16]byte // Internet address of remote host.
Unused [20]byte // Reserved for future use. // original is 20
}

View File

@ -0,0 +1,61 @@
// +build linux
package host
import (
"testing"
)
func TestGetRedhatishVersion(t *testing.T) {
var ret string
c := []string{"Rawhide"}
ret = getRedhatishVersion(c)
if ret != "rawhide" {
t.Errorf("Could not get version rawhide: %v", ret)
}
c = []string{"Fedora release 15 (Lovelock)"}
ret = getRedhatishVersion(c)
if ret != "15" {
t.Errorf("Could not get version fedora: %v", ret)
}
c = []string{"Enterprise Linux Server release 5.5 (Carthage)"}
ret = getRedhatishVersion(c)
if ret != "5.5" {
t.Errorf("Could not get version redhat enterprise: %v", ret)
}
c = []string{""}
ret = getRedhatishVersion(c)
if ret != "" {
t.Errorf("Could not get version with no value: %v", ret)
}
}
func TestGetRedhatishPlatform(t *testing.T) {
var ret string
c := []string{"red hat"}
ret = getRedhatishPlatform(c)
if ret != "redhat" {
t.Errorf("Could not get platform redhat: %v", ret)
}
c = []string{"Fedora release 15 (Lovelock)"}
ret = getRedhatishPlatform(c)
if ret != "fedora" {
t.Errorf("Could not get platform fedora: %v", ret)
}
c = []string{"Enterprise Linux Server release 5.5 (Carthage)"}
ret = getRedhatishPlatform(c)
if ret != "enterprise" {
t.Errorf("Could not get platform redhat enterprise: %v", ret)
}
c = []string{""}
ret = getRedhatishPlatform(c)
if ret != "" {
t.Errorf("Could not get platform with no value: %v", ret)
}
}

View File

@ -0,0 +1,67 @@
package host
import (
"fmt"
"testing"
)
func TestHostInfo(t *testing.T) {
v, err := HostInfo()
if err != nil {
t.Errorf("error %v", err)
}
empty := &HostInfoStat{}
if v == empty {
t.Errorf("Could not get hostinfo %v", v)
}
}
func TestBoot_time(t *testing.T) {
v, err := BootTime()
if err != nil {
t.Errorf("error %v", err)
}
if v == 0 {
t.Errorf("Could not get boot time %v", v)
}
}
func TestUsers(t *testing.T) {
v, err := Users()
if err != nil {
t.Errorf("error %v", err)
}
empty := UserStat{}
for _, u := range v {
if u == empty {
t.Errorf("Could not Users %v", v)
}
}
}
func TestHostInfoStat_String(t *testing.T) {
v := HostInfoStat{
Hostname: "test",
Uptime: 3000,
Procs: 100,
OS: "linux",
Platform: "ubuntu",
}
e := `{"hostname":"test","uptime":3000,"procs":100,"os":"linux","platform":"ubuntu","platform_family":"","platform_version":"","virtualization_system":"","virtualization_role":""}`
if e != fmt.Sprintf("%v", v) {
t.Errorf("HostInfoStat string is invalid: %v", v)
}
}
func TestUserStat_String(t *testing.T) {
v := UserStat{
User: "user",
Terminal: "term",
Host: "host",
Started: 100,
}
e := `{"user":"user","terminal":"term","host":"host","started":100}`
if e != fmt.Sprintf("%v", v) {
t.Errorf("UserStat string is invalid: %v", v)
}
}

View File

@ -0,0 +1,123 @@
// +build windows
package host
import (
"os"
"fmt"
"time"
"runtime"
"strings"
"github.com/StackExchange/wmi"
common "github.com/shirou/gopsutil/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 HostInfo() (*HostInfoStat, error) {
hostname, err := os.Hostname()
if err != nil {
return nil, err
}
ret := &HostInfoStat{
Hostname: hostname,
OS: runtime.GOOS,
}
platform, family, version, err := GetPlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
} else {
return ret, err
}
ret.Uptime, err = BootTime()
if err != nil {
return ret, err
}
procs, err := process.Pids()
if err != nil {
return ret, err
}
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 BootTime() (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 GetPlatformInformation() (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
}

View File

@ -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

View File

@ -0,0 +1,43 @@
// +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
)
// 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

View File

@ -0,0 +1,45 @@
// +build ignore
/*
Input to cgo -godefs.
*/
package host
/*
#define KERNEL
#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
)
// 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 UtTv struct {
TvSec int32
TvUsec int32
}

View File

@ -0,0 +1,634 @@
// 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.
package process
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
}

View File

@ -0,0 +1,10 @@
PID
245
247
248
249
254
262
264
265
267

View File

@ -0,0 +1,149 @@
package process
import (
"encoding/json"
"runtime"
"time"
"github.com/shirou/gopsutil/common"
"github.com/shirou/gopsutil/cpu"
)
var invoke common.Invoker
func init() {
invoke = common.Invoke{}
}
type Process struct {
Pid int32 `json:"pid"`
name string
status string
numCtxSwitches *NumCtxSwitchesStat
uids []int32
gids []int32
numThreads int32
memInfo *MemoryInfoStat
lastCPUTimes *cpu.CPUTimesStat
lastCPUTime time.Time
}
type OpenFilesStat struct {
Path string `json:"path"`
Fd uint64 `json:"fd"`
}
type MemoryInfoStat struct {
RSS uint64 `json:"rss"` // bytes
VMS uint64 `json:"vms"` // bytes
Swap uint64 `json:"swap"` // bytes
}
type RlimitStat struct {
Resource int32 `json:"resource"`
Soft int32 `json:"soft"`
Hard int32 `json:"hard"`
}
type IOCountersStat struct {
ReadCount uint64 `json:"read_count"`
WriteCount uint64 `json:"write_count"`
ReadBytes uint64 `json:"read_bytes"`
WriteBytes uint64 `json:"write_bytes"`
}
type NumCtxSwitchesStat struct {
Voluntary int64 `json:"voluntary"`
Involuntary int64 `json:"involuntary"`
}
func (p Process) String() string {
s, _ := json.Marshal(p)
return string(s)
}
func (o OpenFilesStat) String() string {
s, _ := json.Marshal(o)
return string(s)
}
func (m MemoryInfoStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
func (r RlimitStat) String() string {
s, _ := json.Marshal(r)
return string(s)
}
func (i IOCountersStat) String() string {
s, _ := json.Marshal(i)
return string(s)
}
func (p NumCtxSwitchesStat) String() string {
s, _ := json.Marshal(p)
return string(s)
}
func PidExists(pid int32) (bool, error) {
pids, err := Pids()
if err != nil {
return false, err
}
for _, i := range pids {
if i == pid {
return true, err
}
}
return false, err
}
// If interval is 0, return difference from last call(non-blocking).
// If interval > 0, wait interval sec and return diffrence between start and end.
func (p *Process) CPUPercent(interval time.Duration) (float64, error) {
numcpu := runtime.NumCPU()
calculate := func(t1, t2 *cpu.CPUTimesStat, delta float64) float64 {
if delta == 0 {
return 0
}
delta_proc := (t2.User - t1.User) + (t2.System - t1.System)
overall_percent := ((delta_proc / delta) * 100) * float64(numcpu)
return overall_percent
}
cpuTimes, err := p.CPUTimes()
if err != nil {
return 0, err
}
if interval > 0 {
p.lastCPUTimes = cpuTimes
p.lastCPUTime = time.Now()
time.Sleep(interval)
cpuTimes, err = p.CPUTimes()
if err != nil {
return 0, err
}
} else {
if p.lastCPUTimes == nil {
// invoked first time
p.lastCPUTimes, err = p.CPUTimes()
if err != nil {
return 0, err
}
p.lastCPUTime = time.Now()
return 0, nil
}
}
delta := (time.Now().Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
ret := calculate(p.lastCPUTimes, cpuTimes, float64(delta))
p.lastCPUTimes = cpuTimes
p.lastCPUTime = time.Now()
return ret, nil
}

View File

@ -0,0 +1,421 @@
// +build darwin
package process
import (
"bytes"
"fmt"
"strconv"
"strings"
"syscall"
"unsafe"
"github.com/shirou/gopsutil/common"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/net"
)
// copied from sys/sysctl.h
const (
CTLKern = 1 // "high kernel": proc, limits
KernProc = 14 // struct: process entries
KernProcPID = 1 // by process id
KernProcProc = 8 // only return procs
KernProcAll = 0 // everything
KernProcPathname = 12 // path to executable
)
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
)
type _Ctype_struct___0 struct {
Pad uint64
}
// MemoryInfoExStat is different between OSes
type MemoryInfoExStat struct {
}
type MemoryMapsStat struct {
}
func Pids() ([]int32, error) {
var ret []int32
pids, err := callPs("pid", 0, false)
if err != nil {
return ret, err
}
for _, pid := range pids {
v, err := strconv.Atoi(pid[0])
if err != nil {
return ret, err
}
ret = append(ret, int32(v))
}
return ret, nil
}
func (p *Process) Ppid() (int32, error) {
r, err := callPs("ppid", p.Pid, false)
v, err := strconv.Atoi(r[0][0])
if err != nil {
return 0, err
}
return int32(v), err
}
func (p *Process) Name() (string, error) {
k, err := p.getKProc()
if err != nil {
return "", err
}
return common.IntToString(k.Proc.P_comm[:]), nil
}
func (p *Process) Exe() (string, error) {
return "", common.NotImplementedError
}
func (p *Process) Cmdline() (string, error) {
r, err := callPs("command", p.Pid, false)
if err != nil {
return "", err
}
return strings.Join(r[0], " "), err
}
func (p *Process) CreateTime() (int64, error) {
return 0, common.NotImplementedError
}
func (p *Process) Cwd() (string, error) {
return "", common.NotImplementedError
}
func (p *Process) Parent() (*Process, error) {
rr, err := common.CallLsof(invoke, p.Pid, "-FR")
if err != nil {
return nil, err
}
for _, r := range rr {
if strings.HasPrefix(r, "p") { // skip if process
continue
}
l := string(r)
v, err := strconv.Atoi(strings.Replace(l, "R", "", 1))
if err != nil {
return nil, err
}
return NewProcess(int32(v))
}
return nil, fmt.Errorf("could not find parent line")
}
func (p *Process) Status() (string, error) {
r, err := callPs("state", p.Pid, false)
if err != nil {
return "", err
}
return r[0][0], err
}
func (p *Process) Uids() ([]int32, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
uids := make([]int32, 0, 3)
uids = append(uids, int32(k.Eproc.Pcred.P_ruid), int32(k.Eproc.Ucred.Uid), int32(k.Eproc.Pcred.P_svuid))
return uids, nil
}
func (p *Process) Gids() ([]int32, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
gids := make([]int32, 0, 3)
gids = append(gids, int32(k.Eproc.Pcred.P_rgid), int32(k.Eproc.Ucred.Ngroups), int32(k.Eproc.Pcred.P_svgid))
return gids, nil
}
func (p *Process) Terminal() (string, error) {
return "", common.NotImplementedError
/*
k, err := p.getKProc()
if err != nil {
return "", err
}
ttyNr := uint64(k.Eproc.Tdev)
termmap, err := getTerminalMap()
if err != nil {
return "", err
}
return termmap[ttyNr], nil
*/
}
func (p *Process) Nice() (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return int32(k.Proc.P_nice), nil
}
func (p *Process) IOnice() (int32, error) {
return 0, common.NotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
var rlimit []RlimitStat
return rlimit, common.NotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
return 0, common.NotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
r, err := callPs("utime,stime", p.Pid, true)
if err != nil {
return 0, err
}
return int32(len(r)), nil
}
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, common.NotImplementedError
}
func convertCpuTimes(s string) (ret float64, err error) {
var t int
var _tmp string
if strings.Contains(s, ":") {
_t := strings.Split(s, ":")
hour, err := strconv.Atoi(_t[0])
if err != nil {
return ret, err
}
t += hour * 60 * 100
_tmp = _t[1]
} else {
_tmp = s
}
_t := strings.Split(_tmp, ".")
if err != nil {
return ret, err
}
h, err := strconv.Atoi(_t[0])
t += h * 100
h, err = strconv.Atoi(_t[1])
t += h
return float64(t) / ClockTicks, nil
}
func (p *Process) CPUTimes() (*cpu.CPUTimesStat, error) {
r, err := callPs("utime,stime", p.Pid, false)
if err != nil {
return nil, err
}
utime, err := convertCpuTimes(r[0][0])
if err != nil {
return nil, err
}
stime, err := convertCpuTimes(r[0][1])
if err != nil {
return nil, err
}
ret := &cpu.CPUTimesStat{
CPU: "cpu",
User: utime,
System: stime,
}
return ret, nil
}
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
r, err := callPs("rss,vsize,pagein", p.Pid, false)
if err != nil {
return nil, err
}
rss, err := strconv.Atoi(r[0][0])
if err != nil {
return nil, err
}
vms, err := strconv.Atoi(r[0][1])
if err != nil {
return nil, err
}
pagein, err := strconv.Atoi(r[0][2])
if err != nil {
return nil, err
}
ret := &MemoryInfoStat{
RSS: uint64(rss),
VMS: uint64(vms),
Swap: uint64(pagein),
}
return ret, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryPercent() (float32, error) {
return 0, common.NotImplementedError
}
func (p *Process) Children() ([]*Process, error) {
return nil, common.NotImplementedError
}
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) Connections() ([]net.NetConnectionStat, error) {
return net.NetConnectionsPid("all", p.Pid)
}
func (p *Process) IsRunning() (bool, error) {
return true, common.NotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
var ret []MemoryMapsStat
return &ret, common.NotImplementedError
}
func copyParams(k *KinfoProc, p *Process) error {
return nil
}
func processes() ([]Process, error) {
results := make([]Process, 0, 50)
mib := []int32{CTLKern, KernProc, KernProcAll, 0}
buf, length, err := common.CallSyscall(mib)
if err != nil {
return results, err
}
// get kinfo_proc size
k := KinfoProc{}
procinfoLen := int(unsafe.Sizeof(k))
count := int(length / uint64(procinfoLen))
/*
fmt.Println(length, procinfoLen, count)
b := buf[0*procinfoLen : 0*procinfoLen+procinfoLen]
fmt.Println(b)
kk, err := parseKinfoProc(b)
fmt.Printf("%#v", kk)
*/
// parse buf to procs
for i := 0; i < count; i++ {
b := buf[i*procinfoLen : i*procinfoLen+procinfoLen]
k, err := parseKinfoProc(b)
if err != nil {
continue
}
p, err := NewProcess(int32(k.Proc.P_pid))
if err != nil {
continue
}
copyParams(&k, p)
results = append(results, *p)
}
return results, nil
}
func parseKinfoProc(buf []byte) (KinfoProc, error) {
var k KinfoProc
br := bytes.NewReader(buf)
err := Read(br, LittleEndian, &k)
if err != nil {
return k, err
}
return k, nil
}
func (p *Process) getKProc() (*KinfoProc, error) {
mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
procK := KinfoProc{}
length := uint64(unsafe.Sizeof(procK))
buf := make([]byte, length)
_, _, syserr := syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(unsafe.Pointer(&mib[0])),
uintptr(len(mib)),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&length)),
0,
0)
if syserr != 0 {
return nil, syserr
}
k, err := parseKinfoProc(buf)
if err != nil {
return nil, err
}
return &k, nil
}
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
return p, nil
}
// call ps command.
// Return value deletes Header line(you must not input wrong arg).
// And splited by Space. Caller have responsibility to manage.
// If passed arg pid is 0, get information from all process.
func callPs(arg string, pid int32, threadOption bool) ([][]string, error) {
var cmd []string
if pid == 0 { // will get from all processes.
cmd = []string{"-x", "-o", arg}
} else if threadOption {
cmd = []string{"-x", "-o", arg, "-M", "-p", strconv.Itoa(int(pid))}
} else {
cmd = []string{"-x", "-o", arg, "-p", strconv.Itoa(int(pid))}
}
out, err := invoke.Command("/bin/ps", cmd...)
if err != nil {
return [][]string{}, err
}
lines := strings.Split(string(out), "\n")
var ret [][]string
for _, l := range lines[1:] {
var lr []string
for _, r := range strings.Split(l, " ") {
if r == "" {
continue
}
lr = append(lr, strings.TrimSpace(r))
}
if len(lr) != 0 {
ret = append(ret, lr)
}
}
return ret, nil
}

View File

@ -0,0 +1,234 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_darwin.go
package process
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type Timespec struct {
Sec int64
Nsec int64
}
type Timeval struct {
Sec int64
Usec int32
Pad_cgo_0 [4]byte
}
type Rusage struct {
Utime Timeval
Stime Timeval
Maxrss int64
Ixrss int64
Idrss int64
Isrss int64
Minflt int64
Majflt int64
Nswap int64
Inblock int64
Oublock int64
Msgsnd int64
Msgrcv int64
Nsignals int64
Nvcsw int64
Nivcsw int64
}
type Rlimit struct {
Cur uint64
Max uint64
}
type UGid_t uint32
type KinfoProc struct {
Proc ExternProc
Eproc Eproc
}
type Eproc struct {
Paddr *uint64
Sess *Session
Pcred Upcred
Ucred Uucred
Pad_cgo_0 [4]byte
Vm Vmspace
Ppid int32
Pgid int32
Jobc int16
Pad_cgo_1 [2]byte
Tdev int32
Tpgid int32
Pad_cgo_2 [4]byte
Tsess *Session
Wmesg [8]int8
Xsize int32
Xrssize int16
Xccount int16
Xswrss int16
Pad_cgo_3 [2]byte
Flag int32
Login [12]int8
Spare [4]int32
Pad_cgo_4 [4]byte
}
type Proc struct{}
type Session struct{}
type ucred struct {
Link _Ctype_struct___0
Ref uint64
Posix Posix_cred
Label *Label
Audit Au_session
}
type Uucred struct {
Ref int32
Uid uint32
Ngroups int16
Pad_cgo_0 [2]byte
Groups [16]uint32
}
type Upcred struct {
Pc_lock [72]int8
Pc_ucred *ucred
P_ruid uint32
P_svuid uint32
P_rgid uint32
P_svgid uint32
P_refcnt int32
Pad_cgo_0 [4]byte
}
type Vmspace struct {
Dummy int32
Pad_cgo_0 [4]byte
Dummy2 *int8
Dummy3 [5]int32
Pad_cgo_1 [4]byte
Dummy4 [3]*int8
}
type Sigacts struct{}
type ExternProc struct {
P_un [16]byte
P_vmspace uint64
P_sigacts uint64
Pad_cgo_0 [3]byte
P_flag int32
P_stat int8
P_pid int32
P_oppid int32
P_dupfd int32
Pad_cgo_1 [4]byte
User_stack uint64
Exit_thread uint64
P_debugger int32
Sigwait int32
P_estcpu uint32
P_cpticks int32
P_pctcpu uint32
Pad_cgo_2 [4]byte
P_wchan uint64
P_wmesg uint64
P_swtime uint32
P_slptime uint32
P_realtimer Itimerval
P_rtime Timeval
P_uticks uint64
P_sticks uint64
P_iticks uint64
P_traceflag int32
Pad_cgo_3 [4]byte
P_tracep uint64
P_siglist int32
Pad_cgo_4 [4]byte
P_textvp uint64
P_holdcnt int32
P_sigmask uint32
P_sigignore uint32
P_sigcatch uint32
P_priority uint8
P_usrpri uint8
P_nice int8
P_comm [17]int8
Pad_cgo_5 [4]byte
P_pgrp uint64
P_addr uint64
P_xstat uint16
P_acflag uint16
Pad_cgo_6 [4]byte
P_ru uint64
}
type Itimerval struct {
Interval Timeval
Value Timeval
}
type Vnode struct{}
type Pgrp struct{}
type UserStruct struct{}
type Au_session struct {
Aia_p *AuditinfoAddr
Mask AuMask
}
type Posix_cred struct {
Uid uint32
Ruid uint32
Svuid uint32
Ngroups int16
Pad_cgo_0 [2]byte
Groups [16]uint32
Rgid uint32
Svgid uint32
Gmuid uint32
Flags int32
}
type Label struct{}
type AuditinfoAddr struct {
Auid uint32
Mask AuMask
Termid AuTidAddr
Asid int32
Flags uint64
}
type AuMask struct {
Success uint32
Failure uint32
}
type AuTidAddr struct {
Port int32
Type uint32
Addr [4]uint32
}
type UcredQueue struct {
Next *ucred
Prev **ucred
}

View File

@ -0,0 +1,263 @@
// +build freebsd
package process
import (
"bytes"
"encoding/binary"
"unsafe"
common "github.com/shirou/gopsutil/common"
cpu "github.com/shirou/gopsutil/cpu"
net "github.com/shirou/gopsutil/net"
)
// MemoryInfoExStat is different between OSes
type MemoryInfoExStat struct {
}
type MemoryMapsStat struct {
}
func Pids() ([]int32, error) {
var ret []int32
procs, err := processes()
if err != nil {
return ret, nil
}
for _, p := range procs {
ret = append(ret, p.Pid)
}
return ret, nil
}
func (p *Process) Ppid() (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return k.KiPpid, nil
}
func (p *Process) Name() (string, error) {
k, err := p.getKProc()
if err != nil {
return "", err
}
return string(k.KiComm[:]), nil
}
func (p *Process) Exe() (string, error) {
return "", common.NotImplementedError
}
func (p *Process) Cmdline() (string, error) {
return "", common.NotImplementedError
}
func (p *Process) CreateTime() (int64, error) {
return 0, common.NotImplementedError
}
func (p *Process) Cwd() (string, error) {
return "", common.NotImplementedError
}
func (p *Process) Parent() (*Process, error) {
return p, common.NotImplementedError
}
func (p *Process) Status() (string, error) {
k, err := p.getKProc()
if err != nil {
return "", err
}
return string(k.KiStat[:]), nil
}
func (p *Process) Uids() ([]int32, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
uids := make([]int32, 0, 3)
uids = append(uids, int32(k.KiRuid), int32(k.KiUID), int32(k.KiSvuid))
return uids, nil
}
func (p *Process) Gids() ([]int32, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
gids := make([]int32, 0, 3)
gids = append(gids, int32(k.KiRgid), int32(k.KiNgroups[0]), int32(k.KiSvuid))
return gids, nil
}
func (p *Process) Terminal() (string, error) {
k, err := p.getKProc()
if err != nil {
return "", err
}
ttyNr := uint64(k.KiTdev)
termmap, err := getTerminalMap()
if err != nil {
return "", err
}
return termmap[ttyNr], nil
}
func (p *Process) Nice() (int32, error) {
return 0, common.NotImplementedError
}
func (p *Process) IOnice() (int32, error) {
return 0, common.NotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
var rlimit []RlimitStat
return rlimit, common.NotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
return 0, common.NotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
k, err := p.getKProc()
if err != nil {
return 0, err
}
return k.KiNumthreads, nil
}
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, common.NotImplementedError
}
func (p *Process) CPUTimes() (*cpu.CPUTimesStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
ret := &MemoryInfoStat{
RSS: uint64(k.KiRssize),
VMS: uint64(k.KiSize),
}
return ret, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryPercent() (float32, error) {
return 0, common.NotImplementedError
}
func (p *Process) Children() ([]*Process, error) {
return nil, common.NotImplementedError
}
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) Connections() ([]net.NetConnectionStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return true, common.NotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
var ret []MemoryMapsStat
return &ret, common.NotImplementedError
}
func copyParams(k *KinfoProc, p *Process) error {
return nil
}
func processes() ([]Process, error) {
results := make([]Process, 0, 50)
mib := []int32{CTLKern, KernProc, KernProcProc, 0}
buf, length, err := common.CallSyscall(mib)
if err != nil {
return results, err
}
// get kinfo_proc size
k := KinfoProc{}
procinfoLen := int(unsafe.Sizeof(k))
count := int(length / uint64(procinfoLen))
// parse buf to procs
for i := 0; i < count; i++ {
b := buf[i*procinfoLen : i*procinfoLen+procinfoLen]
k, err := parseKinfoProc(b)
if err != nil {
continue
}
p, err := NewProcess(int32(k.KiPid))
if err != nil {
continue
}
copyParams(&k, p)
results = append(results, *p)
}
return results, nil
}
func parseKinfoProc(buf []byte) (KinfoProc, error) {
var k KinfoProc
br := bytes.NewReader(buf)
err := binary.Read(br, binary.LittleEndian, &k)
if err != nil {
return k, err
}
return k, nil
}
func (p *Process) getKProc() (*KinfoProc, error) {
mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
buf, length, err := common.CallSyscall(mib)
if err != nil {
return nil, err
}
procK := KinfoProc{}
if length != uint64(unsafe.Sizeof(procK)) {
return nil, err
}
k, err := parseKinfoProc(buf)
if err != nil {
return nil, err
}
return &k, nil
}
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
return p, nil
}

View File

@ -0,0 +1,96 @@
// +build freebsd
// +build 386
package process
// copied from sys/sysctl.h
const (
CTLKern = 1 // "high kernel": proc, limits
KernProc = 14 // struct: process entries
KernProcPID = 1 // by process id
KernProcProc = 8 // only return procs
KernProcPathname = 12 // path to executable
)
// copied from sys/user.h
type KinfoProc struct {
KiStructsize int32
KiLayout int32
KiArgs int32
KiPaddr int32
KiAddr int32
KiTracep int32
KiTextvp int32
KiFd int32
KiVmspace int32
KiWchan int32
KiPid int32
KiPpid int32
KiPgid int32
KiTpgid int32
KiSid int32
KiTsid int32
KiJobc [2]byte
KiSpareShort1 [2]byte
KiTdev int32
KiSiglist [16]byte
KiSigmask [16]byte
KiSigignore [16]byte
KiSigcatch [16]byte
KiUID int32
KiRuid int32
KiSvuid int32
KiRgid int32
KiSvgid int32
KiNgroups [2]byte
KiSpareShort2 [2]byte
KiGroups [64]byte
KiSize int32
KiRssize int32
KiSwrss int32
KiTsize int32
KiDsize int32
KiSsize int32
KiXstat [2]byte
KiAcflag [2]byte
KiPctcpu int32
KiEstcpu int32
KiSlptime int32
KiSwtime int32
KiCow int32
KiRuntime int64
KiStart [8]byte
KiChildtime [8]byte
KiFlag int32
KiKflag int32
KiTraceflag int32
KiStat [1]byte
KiNice [1]byte
KiLock [1]byte
KiRqindex [1]byte
KiOncpu [1]byte
KiLastcpu [1]byte
KiOcomm [17]byte
KiWmesg [9]byte
KiLogin [18]byte
KiLockname [9]byte
KiComm [20]byte
KiEmul [17]byte
KiSparestrings [68]byte
KiSpareints [36]byte
KiCrFlags int32
KiJid int32
KiNumthreads int32
KiTid int32
KiPri int32
KiRusage [72]byte
KiRusageCh [72]byte
KiPcb int32
KiKstack int32
KiUdata int32
KiTdaddr int32
KiSpareptrs [24]byte
KiSpareint64s [48]byte
KiSflag int32
KiTdflags int32
}

View File

@ -0,0 +1,96 @@
// +build freebsd
// +build amd64
package process
// copied from sys/sysctl.h
const (
CTLKern = 1 // "high kernel": proc, limits
KernProc = 14 // struct: process entries
KernProcPID = 1 // by process id
KernProcProc = 8 // only return procs
KernProcPathname = 12 // path to executable
)
// copied from sys/user.h
type KinfoProc struct {
KiStructsize int32
KiLayout int32
KiArgs int64
KiPaddr int64
KiAddr int64
KiTracep int64
KiTextvp int64
KiFd int64
KiVmspace int64
KiWchan int64
KiPid int32
KiPpid int32
KiPgid int32
KiTpgid int32
KiSid int32
KiTsid int32
KiJobc [2]byte
KiSpareShort1 [2]byte
KiTdev int32
KiSiglist [16]byte
KiSigmask [16]byte
KiSigignore [16]byte
KiSigcatch [16]byte
KiUID int32
KiRuid int32
KiSvuid int32
KiRgid int32
KiSvgid int32
KiNgroups [2]byte
KiSpareShort2 [2]byte
KiGroups [64]byte
KiSize int64
KiRssize int64
KiSwrss int64
KiTsize int64
KiDsize int64
KiSsize int64
KiXstat [2]byte
KiAcflag [2]byte
KiPctcpu int32
KiEstcpu int32
KiSlptime int32
KiSwtime int32
KiCow int32
KiRuntime int64
KiStart [16]byte
KiChildtime [16]byte
KiFlag int64
KiKflag int64
KiTraceflag int32
KiStat [1]byte
KiNice [1]byte
KiLock [1]byte
KiRqindex [1]byte
KiOncpu [1]byte
KiLastcpu [1]byte
KiOcomm [17]byte
KiWmesg [9]byte
KiLogin [18]byte
KiLockname [9]byte
KiComm [20]byte
KiEmul [17]byte
KiSparestrings [68]byte
KiSpareints [36]byte
KiCrFlags int32
KiJid int32
KiNumthreads int32
KiTid int32
KiPri int32
KiRusage [144]byte
KiRusageCh [144]byte
KiPcb int64
KiKstack int64
KiUdata int64
KiTdaddr int64
KiSpareptrs [48]byte
KiSpareint64s [96]byte
KiSflag int64
KiTdflags int64
}

View File

@ -0,0 +1,656 @@
// +build linux
package process
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/common"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/host"
"github.com/shirou/gopsutil/net"
)
const (
PrioProcess = 0 // linux/resource.h
)
// MemoryInfoExStat is different between OSes
type MemoryInfoExStat struct {
RSS uint64 `json:"rss"` // bytes
VMS uint64 `json:"vms"` // bytes
Shared uint64 `json:"shared"` // bytes
Text uint64 `json:"text"` // bytes
Lib uint64 `json:"lib"` // bytes
Data uint64 `json:"data"` // bytes
Dirty uint64 `json:"dirty"` // bytes
}
func (m MemoryInfoExStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
type MemoryMapsStat struct {
Path string `json:"path"`
Rss uint64 `json:"rss"`
Size uint64 `json:"size"`
Pss uint64 `json:"pss"`
SharedClean uint64 `json:"shared_clean"`
SharedDirty uint64 `json:"shared_dirty"`
PrivateClean uint64 `json:"private_clean"`
PrivateDirty uint64 `json:"private_dirty"`
Referenced uint64 `json:"referenced"`
Anonymous uint64 `json:"anonymous"`
Swap uint64 `json:"swap"`
}
func (m MemoryMapsStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
// Create new Process instance
// This only stores Pid
func NewProcess(pid int32) (*Process, error) {
p := &Process{
Pid: int32(pid),
}
err := p.fillFromStatus()
return p, err
}
func (p *Process) Ppid() (int32, error) {
_, ppid, _, _, _, err := p.fillFromStat()
if err != nil {
return -1, err
}
return ppid, nil
}
func (p *Process) Name() (string, error) {
return p.name, nil
}
func (p *Process) Exe() (string, error) {
return p.fillFromExe()
}
func (p *Process) Cmdline() (string, error) {
return p.fillFromCmdline()
}
func (p *Process) CreateTime() (int64, error) {
_, _, _, createTime, _, err := p.fillFromStat()
if err != nil {
return 0, err
}
return createTime, nil
}
func (p *Process) Cwd() (string, error) {
return p.fillFromCwd()
}
func (p *Process) Parent() (*Process, error) {
r, err := callLsof("R", p.Pid)
if err != nil {
return nil, err
}
if len(r) != 1 { // TODO: pid 1
return nil, fmt.Errorf("wrong number of parents")
}
v, err := strconv.Atoi(r[0])
if err != nil {
return nil, err
}
return NewProcess(int32(v))
}
func (p *Process) Status() (string, error) {
err := p.fillFromStatus()
if err != nil {
return "", err
}
return p.status, nil
}
func (p *Process) Uids() ([]int32, error) {
err := p.fillFromStatus()
if err != nil {
return []int32{}, err
}
return p.uids, nil
}
func (p *Process) Gids() ([]int32, error) {
err := p.fillFromStatus()
if err != nil {
return []int32{}, err
}
return p.gids, nil
}
func (p *Process) Terminal() (string, error) {
terminal, _, _, _, _, err := p.fillFromStat()
if err != nil {
return "", err
}
return terminal, nil
}
func (p *Process) Nice() (int32, error) {
_, _, _, _, nice, err := p.fillFromStat()
if err != nil {
return 0, err
}
return nice, nil
}
func (p *Process) IOnice() (int32, error) {
return 0, common.NotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
return p.fillFromIO()
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
err := p.fillFromStatus()
if err != nil {
return nil, err
}
return p.numCtxSwitches, nil
}
func (p *Process) NumFDs() (int32, error) {
numFds, _, err := p.fillFromfd()
return numFds, err
}
func (p *Process) NumThreads() (int32, error) {
err := p.fillFromStatus()
if err != nil {
return 0, err
}
return p.numThreads, nil
}
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, nil
}
func (p *Process) CPUTimes() (*cpu.CPUTimesStat, error) {
_, _, cpuTimes, _, _, err := p.fillFromStat()
if err != nil {
return nil, err
}
return cpuTimes, nil
}
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
_, _, err := p.fillFromStatm()
if err != nil {
return nil, err
}
return p.memInfo, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
_, memInfoEx, err := p.fillFromStatm()
if err != nil {
return nil, err
}
return memInfoEx, nil
}
func (p *Process) MemoryPercent() (float32, error) {
return 0, common.NotImplementedError
}
func (p *Process) Children() ([]*Process, error) {
return nil, common.NotImplementedError
}
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) Connections() ([]net.NetConnectionStat, error) {
return net.NetConnectionsPid("all", p.Pid)
}
func (p *Process) IsRunning() (bool, error) {
return true, common.NotImplementedError
}
// MemoryMaps get memory maps from /proc/(pid)/smaps
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
pid := p.Pid
var ret []MemoryMapsStat
smapsPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "smaps")
contents, err := ioutil.ReadFile(smapsPath)
if err != nil {
return nil, err
}
lines := strings.Split(string(contents), "\n")
// function of parsing a block
getBlock := func(first_line []string, block []string) (MemoryMapsStat, error) {
m := MemoryMapsStat{}
m.Path = first_line[len(first_line)-1]
for _, line := range block {
if strings.Contains(line, "VmFlags") {
continue
}
field := strings.Split(line, ":")
if len(field) < 2 {
continue
}
v := strings.Trim(field[1], " kB") // remove last "kB"
t, err := strconv.ParseUint(v, 10, 64)
if err != nil {
return m, err
}
switch field[0] {
case "Size":
m.Size = t
case "Rss":
m.Rss = t
case "Pss":
m.Pss = t
case "Shared_Clean":
m.SharedClean = t
case "Shared_Dirty":
m.SharedDirty = t
case "Private_Clean":
m.PrivateClean = t
case "Private_Dirty":
m.PrivateDirty = t
case "Referenced":
m.Referenced = t
case "Anonymous":
m.Anonymous = t
case "Swap":
m.Swap = t
}
}
return m, nil
}
blocks := make([]string, 16)
for _, line := range lines {
field := strings.Split(line, " ")
if strings.HasSuffix(field[0], ":") == false {
// new block section
if len(blocks) > 0 {
g, err := getBlock(field, blocks)
if err != nil {
return &ret, err
}
ret = append(ret, g)
}
// starts new block
blocks = make([]string, 16)
} else {
blocks = append(blocks, line)
}
}
return &ret, nil
}
/**
** Internal functions
**/
// Get num_fds from /proc/(pid)/fd
func (p *Process) fillFromfd() (int32, []*OpenFilesStat, error) {
pid := p.Pid
statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "fd")
d, err := os.Open(statPath)
if err != nil {
return 0, nil, err
}
defer d.Close()
fnames, err := d.Readdirnames(-1)
numFDs := int32(len(fnames))
openfiles := make([]*OpenFilesStat, numFDs)
for _, fd := range fnames {
fpath := filepath.Join(statPath, fd)
filepath, err := os.Readlink(fpath)
if err != nil {
continue
}
t, err := strconv.ParseUint(fd, 10, 64)
if err != nil {
return numFDs, openfiles, err
}
o := &OpenFilesStat{
Path: filepath,
Fd: t,
}
openfiles = append(openfiles, o)
}
return numFDs, openfiles, nil
}
// Get cwd from /proc/(pid)/cwd
func (p *Process) fillFromCwd() (string, error) {
pid := p.Pid
cwdPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "cwd")
cwd, err := os.Readlink(cwdPath)
if err != nil {
return "", err
}
return string(cwd), nil
}
// Get exe from /proc/(pid)/exe
func (p *Process) fillFromExe() (string, error) {
pid := p.Pid
exePath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "exe")
exe, err := os.Readlink(exePath)
if err != nil {
return "", err
}
return string(exe), nil
}
// Get cmdline from /proc/(pid)/cmdline
func (p *Process) fillFromCmdline() (string, error) {
pid := p.Pid
cmdPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "cmdline")
cmdline, err := ioutil.ReadFile(cmdPath)
if err != nil {
return "", err
}
ret := strings.FieldsFunc(string(cmdline), func(r rune) bool {
if r == '\u0000' {
return true
}
return false
})
return strings.Join(ret, " "), nil
}
// Get IO status from /proc/(pid)/io
func (p *Process) fillFromIO() (*IOCountersStat, error) {
pid := p.Pid
ioPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "io")
ioline, err := ioutil.ReadFile(ioPath)
if err != nil {
return nil, err
}
lines := strings.Split(string(ioline), "\n")
ret := &IOCountersStat{}
for _, line := range lines {
field := strings.Fields(line)
if len(field) < 2 {
continue
}
t, err := strconv.ParseUint(field[1], 10, 64)
if err != nil {
return nil, err
}
param := field[0]
if strings.HasSuffix(param, ":") {
param = param[:len(param)-1]
}
switch param {
case "syscr":
ret.ReadCount = t
case "syscw":
ret.WriteCount = t
case "read_bytes":
ret.ReadBytes = t
case "write_bytes":
ret.WriteBytes = t
}
}
return ret, nil
}
// Get memory info from /proc/(pid)/statm
func (p *Process) fillFromStatm() (*MemoryInfoStat, *MemoryInfoExStat, error) {
pid := p.Pid
memPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "statm")
contents, err := ioutil.ReadFile(memPath)
if err != nil {
return nil, nil, err
}
fields := strings.Split(string(contents), " ")
vms, err := strconv.ParseUint(fields[0], 10, 64)
if err != nil {
return nil, nil, err
}
rss, err := strconv.ParseUint(fields[1], 10, 64)
if err != nil {
return nil, nil, err
}
memInfo := &MemoryInfoStat{
RSS: rss * PageSize,
VMS: vms * PageSize,
}
shared, err := strconv.ParseUint(fields[2], 10, 64)
if err != nil {
return nil, nil, err
}
text, err := strconv.ParseUint(fields[3], 10, 64)
if err != nil {
return nil, nil, err
}
lib, err := strconv.ParseUint(fields[4], 10, 64)
if err != nil {
return nil, nil, err
}
dirty, err := strconv.ParseUint(fields[5], 10, 64)
if err != nil {
return nil, nil, err
}
memInfoEx := &MemoryInfoExStat{
RSS: rss * PageSize,
VMS: vms * PageSize,
Shared: shared * PageSize,
Text: text * PageSize,
Lib: lib * PageSize,
Dirty: dirty * PageSize,
}
return memInfo, memInfoEx, nil
}
// Get various status from /proc/(pid)/status
func (p *Process) fillFromStatus() error {
pid := p.Pid
statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "status")
contents, err := ioutil.ReadFile(statPath)
if err != nil {
return err
}
lines := strings.Split(string(contents), "\n")
p.numCtxSwitches = &NumCtxSwitchesStat{}
p.memInfo = &MemoryInfoStat{}
for _, line := range lines {
tabParts := strings.SplitN(line, "\t", 2)
if len(tabParts) < 2 {
continue
}
value := tabParts[1]
switch strings.TrimRight(tabParts[0], ":") {
case "Name":
p.name = strings.Trim(value, " \t")
case "State":
// get between "(" and ")"
s := strings.Index(value, "(") + 1
e := strings.Index(value, ")")
p.status = value[s:e]
case "Uid":
p.uids = make([]int32, 0, 4)
for _, i := range strings.Split(value, "\t") {
v, err := strconv.ParseInt(i, 10, 32)
if err != nil {
return err
}
p.uids = append(p.uids, int32(v))
}
case "Gid":
p.gids = make([]int32, 0, 4)
for _, i := range strings.Split(value, "\t") {
v, err := strconv.ParseInt(i, 10, 32)
if err != nil {
return err
}
p.gids = append(p.gids, int32(v))
}
case "Threads":
v, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return err
}
p.numThreads = int32(v)
case "voluntary_ctxt_switches":
v, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
p.numCtxSwitches.Voluntary = v
case "nonvoluntary_ctxt_switches":
v, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
p.numCtxSwitches.Involuntary = v
case "VmRSS":
value := strings.Trim(value, " kB") // remove last "kB"
v, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return err
}
p.memInfo.RSS = v * 1024
case "VmSize":
value := strings.Trim(value, " kB") // remove last "kB"
v, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return err
}
p.memInfo.VMS = v * 1024
case "VmSwap":
value := strings.Trim(value, " kB") // remove last "kB"
v, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return err
}
p.memInfo.Swap = v * 1024
}
}
return nil
}
func (p *Process) fillFromStat() (string, int32, *cpu.CPUTimesStat, int64, int32, error) {
pid := p.Pid
statPath := filepath.Join("/", "proc", strconv.Itoa(int(pid)), "stat")
contents, err := ioutil.ReadFile(statPath)
if err != nil {
return "", 0, nil, 0, 0, err
}
fields := strings.Fields(string(contents))
termmap, err := getTerminalMap()
terminal := ""
if err == nil {
t, err := strconv.ParseUint(fields[6], 10, 64)
if err != nil {
return "", 0, nil, 0, 0, err
}
terminal = termmap[t]
}
ppid, err := strconv.ParseInt(fields[3], 10, 32)
if err != nil {
return "", 0, nil, 0, 0, err
}
utime, err := strconv.ParseFloat(fields[13], 64)
if err != nil {
return "", 0, nil, 0, 0, err
}
stime, err := strconv.ParseFloat(fields[14], 64)
if err != nil {
return "", 0, nil, 0, 0, err
}
cpuTimes := &cpu.CPUTimesStat{
CPU: "cpu",
User: float64(utime / ClockTicks),
System: float64(stime / ClockTicks),
}
bootTime, _ := host.BootTime()
t, err := strconv.ParseUint(fields[21], 10, 64)
if err != nil {
return "", 0, nil, 0, 0, err
}
ctime := (t / uint64(ClockTicks)) + uint64(bootTime)*1000
createTime := int64(ctime)
// p.Nice = mustParseInt32(fields[18])
// use syscall instead of parse Stat file
snice, _ := syscall.Getpriority(PrioProcess, int(pid))
nice := int32(snice) // FIXME: is this true?
return terminal, int32(ppid), cpuTimes, createTime, nice, nil
}
func Pids() ([]int32, error) {
var ret []int32
d, err := os.Open("/proc")
if err != nil {
return nil, err
}
defer d.Close()
fnames, err := d.Readdirnames(-1)
if err != nil {
return nil, err
}
for _, fname := range fnames {
pid, err := strconv.ParseInt(fname, 10, 32)
if err != nil {
// if not numeric name, just skip
continue
}
ret = append(ret, int32(pid))
}
return ret, nil
}
func callLsof(arg string, pid int32) ([]string, error) {
var cmd []string
if pid == 0 { // will get from all processes.
cmd = []string{"-F" + arg}
} else {
cmd = []string{"-a", "-F" + arg, "-p", strconv.Itoa(int(pid))}
}
out, err := invoke.Command("/usr/bin/lsof", cmd...)
if err != nil {
return []string{}, err
}
lines := strings.Split(string(out), "\n")
var ret []string
for _, l := range lines[1:] {
if strings.HasPrefix(l, arg) {
ret = append(ret, l[1:]) // delete first char
}
}
return ret, nil
}

View File

@ -0,0 +1,9 @@
// +build linux
// +build 386
package process
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE)
)

View File

@ -0,0 +1,9 @@
// +build linux
// +build amd64
package process
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE)
)

View File

@ -0,0 +1,9 @@
// +build linux
// +build arm
package process
const (
ClockTicks = 100 // C.sysconf(C._SC_CLK_TCK)
PageSize = 4096 // C.sysconf(C._SC_PAGE_SIZE)
)

View File

@ -0,0 +1,102 @@
// +build linux freebsd darwin
package process
import (
"os"
"os/exec"
"os/user"
"strconv"
"strings"
"syscall"
)
// POSIX
func getTerminalMap() (map[uint64]string, error) {
ret := make(map[uint64]string)
var termfiles []string
d, err := os.Open("/dev")
if err != nil {
return nil, err
}
defer d.Close()
devnames, err := d.Readdirnames(-1)
for _, devname := range devnames {
if strings.HasPrefix(devname, "/dev/tty") {
termfiles = append(termfiles, "/dev/tty/"+devname)
}
}
ptsd, err := os.Open("/dev/pts")
if err != nil {
return nil, err
}
defer ptsd.Close()
ptsnames, err := ptsd.Readdirnames(-1)
for _, ptsname := range ptsnames {
termfiles = append(termfiles, "/dev/pts/"+ptsname)
}
for _, name := range termfiles {
stat := syscall.Stat_t{}
if err = syscall.Stat(name, &stat); err != nil {
return nil, err
}
rdev := uint64(stat.Rdev)
ret[rdev] = strings.Replace(name, "/dev", "", -1)
}
return ret, nil
}
func (p *Process) SendSignal(sig syscall.Signal) error {
sigAsStr := "INT"
switch sig {
case syscall.SIGSTOP:
sigAsStr = "STOP"
case syscall.SIGCONT:
sigAsStr = "CONT"
case syscall.SIGTERM:
sigAsStr = "TERM"
case syscall.SIGKILL:
sigAsStr = "KILL"
}
cmd := exec.Command("kill", "-s", sigAsStr, strconv.Itoa(int(p.Pid)))
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
return err
}
return nil
}
func (p *Process) Suspend() error {
return p.SendSignal(syscall.SIGSTOP)
}
func (p *Process) Resume() error {
return p.SendSignal(syscall.SIGCONT)
}
func (p *Process) Terminate() error {
return p.SendSignal(syscall.SIGTERM)
}
func (p *Process) Kill() error {
return p.SendSignal(syscall.SIGKILL)
}
func (p *Process) Username() (string, error) {
uids, err := p.Uids()
if err != nil {
return "", err
}
if len(uids) > 0 {
u, err := user.LookupId(strconv.Itoa(int(uids[0])))
if err != nil {
return "", err
}
return u.Username, nil
}
return "", nil
}

View File

@ -0,0 +1,19 @@
// +build linux freebsd
package process
import (
"os"
"syscall"
"testing"
)
func Test_SendSignal(t *testing.T) {
checkPid := os.Getpid()
p, _ := NewProcess(int32(checkPid))
err := p.SendSignal(syscall.SIGCONT)
if err != nil {
t.Errorf("send signal %v", err)
}
}

View File

@ -0,0 +1,306 @@
package process
import (
"os"
"runtime"
"strings"
"sync"
"testing"
"time"
"github.com/shirou/gopsutil/common"
)
var mu sync.Mutex
func testGetProcess() Process {
checkPid := os.Getpid() // process.test
ret, _ := NewProcess(int32(checkPid))
return *ret
}
func Test_Pids(t *testing.T) {
ret, err := Pids()
if err != nil {
t.Errorf("error %v", err)
}
if len(ret) == 0 {
t.Errorf("could not get pids %v", ret)
}
}
func Test_Pids_Fail(t *testing.T) {
if runtime.GOOS != "darwin" {
t.Skip("darwin only")
}
mu.Lock()
defer mu.Unlock()
invoke = common.FakeInvoke{Suffix: "fail"}
ret, err := Pids()
invoke = common.Invoke{}
if err != nil {
t.Errorf("error %v", err)
}
if len(ret) != 9 {
t.Errorf("wrong getted pid nums: %v/%d", ret, len(ret))
}
}
func Test_Pid_exists(t *testing.T) {
checkPid := os.Getpid()
ret, err := PidExists(int32(checkPid))
if err != nil {
t.Errorf("error %v", err)
}
if ret == false {
t.Errorf("could not get process exists: %v", ret)
}
}
func Test_NewProcess(t *testing.T) {
checkPid := os.Getpid()
ret, err := NewProcess(int32(checkPid))
if err != nil {
t.Errorf("error %v", err)
}
empty := &Process{}
if runtime.GOOS != "windows" { // Windows pid is 0
if empty == ret {
t.Errorf("error %v", ret)
}
}
}
func Test_Process_memory_maps(t *testing.T) {
checkPid := os.Getpid()
ret, err := NewProcess(int32(checkPid))
mmaps, err := ret.MemoryMaps(false)
if err != nil {
t.Errorf("memory map get error %v", err)
}
empty := MemoryMapsStat{}
for _, m := range *mmaps {
if m == empty {
t.Errorf("memory map get error %v", m)
}
}
}
func Test_Process_MemoryInfo(t *testing.T) {
p := testGetProcess()
v, err := p.MemoryInfo()
if err != nil {
t.Errorf("geting memory info error %v", err)
}
empty := MemoryInfoStat{}
if v == nil || *v == empty {
t.Errorf("could not get memory info %v", v)
}
}
func Test_Process_CmdLine(t *testing.T) {
p := testGetProcess()
v, err := p.Cmdline()
if err != nil {
t.Errorf("geting cmdline error %v", err)
}
if !strings.Contains(v, "process.test") {
t.Errorf("invalid cmd line %v", v)
}
}
func Test_Process_Ppid(t *testing.T) {
p := testGetProcess()
v, err := p.Ppid()
if err != nil {
t.Errorf("geting ppid error %v", err)
}
if v == 0 {
t.Errorf("return value is 0 %v", v)
}
}
func Test_Process_Status(t *testing.T) {
p := testGetProcess()
v, err := p.Status()
if err != nil {
t.Errorf("geting status error %v", err)
}
if !strings.HasPrefix(v, "S") && v != "running" && v != "sleeping" {
t.Errorf("could not get state %v", v)
}
}
func Test_Process_Terminal(t *testing.T) {
p := testGetProcess()
_, err := p.Terminal()
if err != nil {
t.Errorf("geting terminal error %v", err)
}
/*
if v == "" {
t.Errorf("could not get terminal %v", v)
}
*/
}
func Test_Process_IOCounters(t *testing.T) {
p := testGetProcess()
v, err := p.IOCounters()
if err != nil {
t.Errorf("geting iocounter error %v", err)
return
}
empty := &IOCountersStat{}
if v == empty {
t.Errorf("error %v", v)
}
}
func Test_Process_NumCtx(t *testing.T) {
p := testGetProcess()
_, err := p.NumCtxSwitches()
if err != nil {
t.Errorf("geting numctx error %v", err)
return
}
}
func Test_Process_Nice(t *testing.T) {
p := testGetProcess()
n, err := p.Nice()
if err != nil {
t.Errorf("geting nice error %v", err)
}
if n != 0 && n != 20 && n != 8 {
t.Errorf("invalid nice: %d", n)
}
}
func Test_Process_NumThread(t *testing.T) {
p := testGetProcess()
n, err := p.NumThreads()
if err != nil {
t.Errorf("geting NumThread error %v", err)
}
if n < 0 {
t.Errorf("invalid NumThread: %d", n)
}
}
func Test_Process_Name(t *testing.T) {
p := testGetProcess()
n, err := p.Name()
if err != nil {
t.Errorf("geting name error %v", err)
}
if !strings.Contains(n, "process.test") {
t.Errorf("invalid Exe %s", n)
}
}
func Test_Process_Exe(t *testing.T) {
p := testGetProcess()
n, err := p.Exe()
if err != nil {
t.Errorf("geting Exe error %v", err)
}
if !strings.Contains(n, "process.test") {
t.Errorf("invalid Exe %s", n)
}
}
func Test_Process_CpuPercent(t *testing.T) {
p := testGetProcess()
percent, err := p.CPUPercent(0)
if err != nil {
t.Errorf("error %v", err)
}
duration := time.Duration(1000) * time.Microsecond
time.Sleep(duration)
percent, err = p.CPUPercent(0)
if err != nil {
t.Errorf("error %v", err)
}
numcpu := runtime.NumCPU()
// if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
if percent < 0.0 {
t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu)
}
}
func Test_Process_CpuPercentLoop(t *testing.T) {
p := testGetProcess()
numcpu := runtime.NumCPU()
for i := 0; i < 2; i++ {
duration := time.Duration(100) * time.Microsecond
percent, err := p.CPUPercent(duration)
if err != nil {
t.Errorf("error %v", err)
}
// if percent < 0.0 || percent > 100.0*float64(numcpu) { // TODO
if percent < 0.0 {
t.Fatalf("CPUPercent value is invalid: %f, %d", percent, numcpu)
}
}
}
func Test_Process_CreateTime(t *testing.T) {
p := testGetProcess()
c, err := p.CreateTime()
if err != nil {
t.Errorf("error %v", err)
}
if c < 1420000000 {
t.Errorf("process created time is wrong.")
}
}
func Test_Parent(t *testing.T) {
p := testGetProcess()
c, err := p.Parent()
if err != nil {
t.Fatalf("error %v", err)
}
if c == nil {
t.Fatalf("could not get parent")
}
if c.Pid == 0 {
t.Fatalf("wrong parent pid")
}
}
func Test_Connections(t *testing.T) {
p := testGetProcess()
c, err := p.Connections()
if err != nil {
t.Fatalf("error %v", err)
}
// TODO:
// Since go test open no conneciton, ret is empty.
// should invoke child process or other solutions.
if len(c) != 0 {
t.Fatalf("wrong connections")
}
}

View File

@ -0,0 +1,344 @@
// +build windows
package process
import (
"errors"
"fmt"
"syscall"
"time"
"unsafe"
"github.com/StackExchange/wmi"
"github.com/shirou/w32"
common "github.com/shirou/gopsutil/common"
cpu "github.com/shirou/gopsutil/cpu"
net "github.com/shirou/gopsutil/net"
)
const (
NoMoreFiles = 0x12
MaxPathLength = 260
)
type SystemProcessInformation struct {
NextEntryOffset uint64
NumberOfThreads uint64
Reserved1 [48]byte
Reserved2 [3]byte
UniqueProcessID uintptr
Reserved3 uintptr
HandleCount uint64
Reserved4 [4]byte
Reserved5 [11]byte
PeakPagefileUsage uint64
PrivatePageCount uint64
Reserved6 [6]uint64
}
// Memory_info_ex is different between OSes
type MemoryInfoExStat struct {
}
type MemoryMapsStat struct {
}
type Win32_Process struct {
Name string
ExecutablePath *string
CommandLine *string
Priority uint32
CreationDate *time.Time
ProcessId uint32
ThreadCount uint32
/*
CSCreationClassName string
CSName string
Caption *string
CreationClassName string
Description *string
ExecutionState *uint16
HandleCount uint32
KernelModeTime uint64
MaximumWorkingSetSize *uint32
MinimumWorkingSetSize *uint32
OSCreationClassName string
OSName string
OtherOperationCount uint64
OtherTransferCount uint64
PageFaults uint32
PageFileUsage uint32
ParentProcessId uint32
PeakPageFileUsage uint32
PeakVirtualSize uint64
PeakWorkingSetSize uint32
PrivatePageCount uint64
ReadOperationCount uint64
ReadTransferCount uint64
Status *string
TerminationDate *time.Time
UserModeTime uint64
WorkingSetSize uint64
WriteOperationCount uint64
WriteTransferCount uint64
*/
}
func Pids() ([]int32, error) {
var ret []int32
procs, err := processes()
if err != nil {
return ret, nil
}
for _, proc := range procs {
ret = append(ret, proc.Pid)
}
return ret, nil
}
func (p *Process) Ppid() (int32, error) {
ret, _, _, err := p.getFromSnapProcess(p.Pid)
if err != nil {
return 0, err
}
return ret, nil
}
func GetWin32Proc(pid int32) ([]Win32_Process, error) {
var dst []Win32_Process
query := fmt.Sprintf("WHERE ProcessId = %d", pid)
q := wmi.CreateQuery(&dst, query)
err := wmi.Query(q, &dst)
if err != nil {
return []Win32_Process{}, fmt.Errorf("could not get win32Proc: %s", err)
}
if len(dst) != 1 {
return []Win32_Process{}, fmt.Errorf("could not get win32Proc: empty")
}
return dst, nil
}
func (p *Process) Name() (string, error) {
dst, err := GetWin32Proc(p.Pid)
if err != nil {
return "", fmt.Errorf("could not get Name: %s", err)
}
return dst[0].Name, nil
}
func (p *Process) Exe() (string, error) {
dst, err := GetWin32Proc(p.Pid)
if err != nil {
return "", fmt.Errorf("could not get ExecutablePath: %s", err)
}
return *dst[0].ExecutablePath, nil
}
func (p *Process) Cmdline() (string, error) {
dst, err := GetWin32Proc(p.Pid)
if err != nil {
return "", fmt.Errorf("could not get CommandLine: %s", err)
}
return *dst[0].CommandLine, nil
}
func (p *Process) CreateTime() (int64, error) {
dst, err := GetWin32Proc(p.Pid)
if err != nil {
return 0, fmt.Errorf("could not get CreationDate: %s", err)
}
date := *dst[0].CreationDate
return date.Unix(), nil
}
func (p *Process) Cwd() (string, error) {
return "", common.NotImplementedError
}
func (p *Process) Parent() (*Process, error) {
return p, common.NotImplementedError
}
func (p *Process) Status() (string, error) {
return "", common.NotImplementedError
}
func (p *Process) Username() (string, error) {
return "", common.NotImplementedError
}
func (p *Process) Uids() ([]int32, error) {
var uids []int32
return uids, common.NotImplementedError
}
func (p *Process) Gids() ([]int32, error) {
var gids []int32
return gids, common.NotImplementedError
}
func (p *Process) Terminal() (string, error) {
return "", common.NotImplementedError
}
// Nice returnes priority in Windows
func (p *Process) Nice() (int32, error) {
dst, err := GetWin32Proc(p.Pid)
if err != nil {
return 0, fmt.Errorf("could not get Priority: %s", err)
}
return int32(dst[0].Priority), nil
}
func (p *Process) IOnice() (int32, error) {
return 0, common.NotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
var rlimit []RlimitStat
return rlimit, common.NotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
return 0, common.NotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
dst, err := GetWin32Proc(p.Pid)
if err != nil {
return 0, fmt.Errorf("could not get ThreadCount: %s", err)
}
return int32(dst[0].ThreadCount), nil
}
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, common.NotImplementedError
}
func (p *Process) CPUTimes() (*cpu.CPUTimesStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryPercent() (float32, error) {
return 0, common.NotImplementedError
}
func (p *Process) Children() ([]*Process, error) {
return nil, common.NotImplementedError
}
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) Connections() ([]net.NetConnectionStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return true, common.NotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
ret := make([]MemoryMapsStat, 0)
return &ret, common.NotImplementedError
}
func NewProcess(pid int32) (*Process, error) {
p := &Process{Pid: pid}
return p, nil
}
func (p *Process) SendSignal(sig syscall.Signal) error {
return common.NotImplementedError
}
func (p *Process) Suspend() error {
return common.NotImplementedError
}
func (p *Process) Resume() error {
return common.NotImplementedError
}
func (p *Process) Terminate() error {
return common.NotImplementedError
}
func (p *Process) Kill() error {
return common.NotImplementedError
}
func (p *Process) getFromSnapProcess(pid int32) (int32, int32, string, error) {
snap := w32.CreateToolhelp32Snapshot(w32.TH32CS_SNAPPROCESS, uint32(pid))
if snap == 0 {
return 0, 0, "", syscall.GetLastError()
}
defer w32.CloseHandle(snap)
var pe32 w32.PROCESSENTRY32
pe32.DwSize = uint32(unsafe.Sizeof(pe32))
if w32.Process32First(snap, &pe32) == false {
return 0, 0, "", syscall.GetLastError()
}
if pe32.Th32ProcessID == uint32(pid) {
szexe := syscall.UTF16ToString(pe32.SzExeFile[:])
return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
}
for w32.Process32Next(snap, &pe32) {
if pe32.Th32ProcessID == uint32(pid) {
szexe := syscall.UTF16ToString(pe32.SzExeFile[:])
return int32(pe32.Th32ParentProcessID), int32(pe32.CntThreads), szexe, nil
}
}
return 0, 0, "", errors.New("Couldn't find pid:" + string(pid))
}
// Get processes
func processes() ([]*Process, error) {
var dst []Win32_Process
q := wmi.CreateQuery(&dst, "")
err := wmi.Query(q, &dst)
if err != nil {
return []*Process{}, err
}
if len(dst) == 0 {
return []*Process{}, fmt.Errorf("could not get Process")
}
results := make([]*Process, 0, len(dst))
for _, proc := range dst {
p, err := NewProcess(int32(proc.ProcessId))
if err != nil {
continue
}
results = append(results, p)
}
return results, nil
}
func getProcInfo(pid int32) (*SystemProcessInformation, error) {
initialBufferSize := uint64(0x4000)
bufferSize := initialBufferSize
buffer := make([]byte, bufferSize)
var sysProcInfo SystemProcessInformation
ret, _, _ := common.ProcNtQuerySystemInformation.Call(
uintptr(unsafe.Pointer(&sysProcInfo)),
uintptr(unsafe.Pointer(&buffer[0])),
uintptr(unsafe.Pointer(&bufferSize)),
uintptr(unsafe.Pointer(&bufferSize)))
if ret != 0 {
return nil, syscall.GetLastError()
}
return &sysProcInfo, nil
}

View File

@ -0,0 +1,160 @@
// 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.
// Hand Writing
// - all pointer in ExternProc to uint64
// +build ignore
/*
Input to cgo -godefs.
*/
// +godefs map struct_in_addr [4]byte /* in_addr */
// +godefs map struct_in6_addr [16]byte /* in6_addr */
// +godefs map struct_ [16]byte /* in6_addr */
package process
/*
#define __DARWIN_UNIX03 0
#define KERNEL
#define _DARWIN_USE_64_BIT_INODE
#include <dirent.h>
#include <fcntl.h>
#include <signal.h>
#include <termios.h>
#include <unistd.h>
#include <mach/mach.h>
#include <mach/message.h>
#include <sys/event.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/select.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <net/bpf.h>
#include <net/if_dl.h>
#include <net/if_var.h>
#include <net/route.h>
#include <netinet/in.h>
#include <sys/sysctl.h>
#include <sys/ucred.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/_types/_timeval.h>
#include <sys/appleapiopts.h>
#include <sys/cdefs.h>
#include <sys/param.h>
#include <bsm/audit.h>
#include <sys/queue.h>
enum {
sizeofPtr = sizeof(void*),
};
union sockaddr_all {
struct sockaddr s1; // this one gets used for fields
struct sockaddr_in s2; // these pad it out
struct sockaddr_in6 s3;
struct sockaddr_un s4;
struct sockaddr_dl s5;
};
struct sockaddr_any {
struct sockaddr addr;
char pad[sizeof(union sockaddr_all) - sizeof(struct sockaddr)];
};
struct ucred_queue {
struct ucred *tqe_next;
struct ucred **tqe_prev;
TRACEBUF
};
*/
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
)
// Basic types
type (
_C_short C.short
_C_int C.int
_C_long C.long
_C_long_long C.longlong
)
// Time
type Timespec C.struct_timespec
type Timeval C.struct_timeval
// Processes
type Rusage C.struct_rusage
type Rlimit C.struct_rlimit
type UGid_t C.gid_t
type KinfoProc C.struct_kinfo_proc
type Eproc C.struct_eproc
type Proc C.struct_proc
type Session C.struct_session
type ucred C.struct_ucred
type Uucred C.struct__ucred
type Upcred C.struct__pcred
type Vmspace C.struct_vmspace
type Sigacts C.struct_sigacts
type ExternProc C.struct_extern_proc
type Itimerval C.struct_itimerval
type Vnode C.struct_vnode
type Pgrp C.struct_pgrp
type UserStruct C.struct_user
type Au_session C.struct_au_session
type Posix_cred C.struct_posix_cred
type Label C.struct_label
type AuditinfoAddr C.struct_auditinfo_addr
type AuMask C.struct_au_mask
type AuTidAddr C.struct_au_tid_addr
// TAILQ(ucred)
type UcredQueue C.struct_ucred_queue

View File

@ -12,7 +12,7 @@ import (
) )
type Specification struct { type Specification struct {
PidFile string `toml:pid_file` PidFile string
Exe string Exe string
Prefix string Prefix string
} }