Updated gopsutil

This commit is contained in:
Diptanu Choudhury
2016-05-09 08:19:04 -07:00
parent f390261cd0
commit 445b181fec
53 changed files with 2007 additions and 808 deletions

View File

@@ -22,7 +22,7 @@ func NewCPUFingerprint(logger *log.Logger) Fingerprint {
}
func (f *CPUFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
cpuInfo, err := cpu.CPUInfo()
cpuInfo, err := cpu.Info()
if err != nil {
f.logger.Println("[WARN] Error reading CPU information:", err)
return false, err

View File

@@ -25,7 +25,7 @@ func NewHostFingerprint(logger *log.Logger) Fingerprint {
}
func (f *HostFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
hostInfo, err := host.HostInfo()
hostInfo, err := host.Info()
if err != nil {
f.logger.Println("[WARN] Error retrieving host information: ", err)
return false, err

View File

@@ -7,7 +7,7 @@ import (
"strings"
)
type CPUTimesStat struct {
type TimesStat struct {
CPU string `json:"cpu"`
User float64 `json:"user"`
System float64 `json:"system"`
@@ -18,33 +18,33 @@ type CPUTimesStat struct {
Softirq float64 `json:"softirq"`
Steal float64 `json:"steal"`
Guest float64 `json:"guest"`
GuestNice float64 `json:"guest_nice"`
GuestNice float64 `json:"guestNice"`
Stolen float64 `json:"stolen"`
}
type CPUInfoStat struct {
type InfoStat struct {
CPU int32 `json:"cpu"`
VendorID string `json:"vendor_id"`
VendorID string `json:"vendorId"`
Family string `json:"family"`
Model string `json:"model"`
Stepping int32 `json:"stepping"`
PhysicalID string `json:"physical_id"`
CoreID string `json:"core_id"`
PhysicalID string `json:"physicalId"`
CoreID string `json:"coreId"`
Cores int32 `json:"cores"`
ModelName string `json:"model_name"`
ModelName string `json:"modelName"`
Mhz float64 `json:"mhz"`
CacheSize int32 `json:"cache_size"`
CacheSize int32 `json:"cacheSize"`
Flags []string `json:"flags"`
}
var lastCPUTimes []CPUTimesStat
var lastPerCPUTimes []CPUTimesStat
var lastCPUTimes []TimesStat
var lastPerCPUTimes []TimesStat
func CPUCounts(logical bool) (int, error) {
func Counts(logical bool) (int, error) {
return runtime.NumCPU(), nil
}
func (c CPUTimesStat) String() string {
func (c TimesStat) String() string {
v := []string{
`"cpu":"` + c.CPU + `"`,
`"user":` + strconv.FormatFloat(c.User, 'f', 1, 64),
@@ -56,14 +56,21 @@ func (c CPUTimesStat) String() string {
`"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64),
`"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64),
`"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64),
`"guest_nice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),
`"guestNice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),
`"stolen":` + strconv.FormatFloat(c.Stolen, 'f', 1, 64),
}
return `{` + strings.Join(v, ",") + `}`
}
func (c CPUInfoStat) String() string {
// Total returns the total number of seconds in a CPUTimesStat
func (c TimesStat) Total() float64 {
total := c.User + c.System + c.Nice + c.Iowait + c.Irq + c.Softirq + c.Steal +
c.Guest + c.GuestNice + c.Idle + c.Stolen
return total
}
func (c InfoStat) String() string {
s, _ := json.Marshal(c)
return string(s)
}

View File

@@ -21,7 +21,7 @@ const (
// default value. from time.h
var ClocksPerSec = float64(128)
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
func Times(percpu bool) ([]TimesStat, error) {
if percpu {
return perCPUTimes()
}
@@ -30,15 +30,18 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
}
// Returns only one CPUInfoStat on FreeBSD
func CPUInfo() ([]CPUInfoStat, error) {
var ret []CPUInfoStat
out, err := exec.Command("/usr/sbin/sysctl", "machdep.cpu").Output()
func Info() ([]InfoStat, error) {
var ret []InfoStat
sysctl, err := exec.LookPath("/usr/sbin/sysctl")
if err != nil {
return ret, err
}
out, err := exec.Command(sysctl, "machdep.cpu").Output()
if err != nil {
return ret, err
}
c := CPUInfoStat{}
c := InfoStat{}
for _, line := range strings.Split(string(out), "\n") {
values := strings.Fields(line)
if len(values) < 1 {
@@ -87,7 +90,7 @@ func CPUInfo() ([]CPUInfoStat, error) {
// Use the rated frequency of the CPU. This is a static value and does not
// account for low power or Turbo Boost modes.
out, err = exec.Command("/usr/sbin/sysctl", "hw.cpufrequency").Output()
out, err = exec.Command(sysctl, "hw.cpufrequency").Output()
if err != nil {
return ret, err
}

View File

@@ -25,7 +25,7 @@ import (
// these CPU times for darwin is borrowed from influxdb/telegraf.
func perCPUTimes() ([]CPUTimesStat, error) {
func perCPUTimes() ([]TimesStat, error) {
var (
count C.mach_msg_type_number_t
cpuload *C.processor_cpu_load_info_data_t
@@ -59,7 +59,7 @@ func perCPUTimes() ([]CPUTimesStat, error) {
bbuf := bytes.NewBuffer(buf)
var ret []CPUTimesStat
var ret []TimesStat
for i := 0; i < int(ncpu); i++ {
err := binary.Read(bbuf, binary.LittleEndian, &cpu_ticks)
@@ -67,7 +67,7 @@ func perCPUTimes() ([]CPUTimesStat, error) {
return nil, err
}
c := CPUTimesStat{
c := TimesStat{
CPU: fmt.Sprintf("cpu%d", i),
User: float64(cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
System: float64(cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
@@ -81,7 +81,7 @@ func perCPUTimes() ([]CPUTimesStat, error) {
return ret, nil
}
func allCPUTimes() ([]CPUTimesStat, error) {
func allCPUTimes() ([]TimesStat, error) {
var count C.mach_msg_type_number_t = C.HOST_CPU_LOAD_INFO_COUNT
var cpuload C.host_cpu_load_info_data_t
@@ -94,7 +94,7 @@ func allCPUTimes() ([]CPUTimesStat, error) {
return nil, fmt.Errorf("host_statistics error=%d", status)
}
c := CPUTimesStat{
c := TimesStat{
CPU: "cpu-total",
User: float64(cpuload.cpu_ticks[C.CPU_STATE_USER]) / ClocksPerSec,
System: float64(cpuload.cpu_ticks[C.CPU_STATE_SYSTEM]) / ClocksPerSec,
@@ -102,6 +102,6 @@ func allCPUTimes() ([]CPUTimesStat, error) {
Idle: float64(cpuload.cpu_ticks[C.CPU_STATE_IDLE]) / ClocksPerSec,
}
return []CPUTimesStat{c}, nil
return []TimesStat{c}, nil
}

View File

@@ -5,10 +5,10 @@ package cpu
import "github.com/shirou/gopsutil/internal/common"
func perCPUTimes() ([]CPUTimesStat, error) {
return []CPUTimesStat{}, common.NotImplementedError
func perCPUTimes() ([]TimesStat, error) {
return []TimesStat{}, common.ErrNotImplementedError
}
func allCPUTimes() ([]CPUTimesStat, error) {
return []CPUTimesStat{}, common.NotImplementedError
func allCPUTimes() ([]TimesStat, error) {
return []TimesStat{}, common.ErrNotImplementedError
}

View File

@@ -25,7 +25,11 @@ const (
var ClocksPerSec = float64(128)
func init() {
out, err := exec.Command("/usr/bin/getconf", "CLK_TCK").Output()
getconf, err := exec.LookPath("/usr/bin/getconf")
if err != nil {
return
}
out, err := exec.Command(getconf, "CLK_TCK").Output()
// ignore errors
if err == nil {
i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
@@ -35,14 +39,14 @@ func init() {
}
}
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
var ret []CPUTimesStat
func Times(percpu bool) ([]TimesStat, error) {
var ret []TimesStat
var sysctlCall string
var ncpu int
if percpu {
sysctlCall = "kern.cp_times"
ncpu, _ = CPUCounts(true)
ncpu, _ = Counts(true)
} else {
sysctlCall = "kern.cp_time"
ncpu = 1
@@ -76,7 +80,7 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
return ret, err
}
c := CPUTimesStat{
c := TimesStat{
User: float64(user / ClocksPerSec),
Nice: float64(nice / ClocksPerSec),
System: float64(sys / ClocksPerSec),
@@ -96,13 +100,13 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
}
// Returns only one CPUInfoStat on FreeBSD
func CPUInfo() ([]CPUInfoStat, error) {
func Info() ([]InfoStat, error) {
filename := "/var/run/dmesg.boot"
lines, _ := common.ReadLines(filename)
var ret []CPUInfoStat
var ret []InfoStat
c := CPUInfoStat{}
c := InfoStat{}
for _, line := range lines {
if matches := regexp.MustCompile(`CPU:\s+(.+) \(([\d.]+).+\)`).FindStringSubmatch(line); matches != nil {
c.ModelName = matches[1]

View File

@@ -15,7 +15,11 @@ import (
var cpu_tick = float64(100)
func init() {
out, err := exec.Command("/usr/bin/getconf", "CLK_TCK").Output()
getconf, err := exec.LookPath("/usr/bin/getconf")
if err != nil {
return
}
out, err := exec.Command(getconf, "CLK_TCK").Output()
// ignore errors
if err == nil {
i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
@@ -25,7 +29,7 @@ func init() {
}
}
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
func Times(percpu bool) ([]TimesStat, error) {
filename := common.HostProc("stat")
var lines = []string{}
if percpu {
@@ -37,13 +41,13 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
break
}
lines = append(lines, line)
startIdx += 1
startIdx++
}
} else {
lines, _ = common.ReadLinesOffsetN(filename, 0, 1)
}
ret := make([]CPUTimesStat, 0, len(lines))
ret := make([]TimesStat, 0, len(lines))
for _, line := range lines {
ct, err := parseStatLine(line)
@@ -56,13 +60,13 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
return ret, nil
}
func sysCpuPath(cpu int32, relPath string) string {
func sysCPUPath(cpu int32, relPath string) string {
return common.HostSys(fmt.Sprintf("devices/system/cpu/cpu%d", cpu), relPath)
}
func finishCPUInfo(c *CPUInfoStat) error {
func finishCPUInfo(c *InfoStat) error {
if c.Mhz == 0 {
lines, err := common.ReadLines(sysCpuPath(c.CPU, "cpufreq/cpuinfo_max_freq"))
lines, err := common.ReadLines(sysCPUPath(c.CPU, "cpufreq/cpuinfo_max_freq"))
if err == nil {
value, err := strconv.ParseFloat(lines[0], 64)
if err != nil {
@@ -72,7 +76,7 @@ func finishCPUInfo(c *CPUInfoStat) error {
}
}
if len(c.CoreID) == 0 {
lines, err := common.ReadLines(sysCpuPath(c.CPU, "topology/core_id"))
lines, err := common.ReadLines(sysCPUPath(c.CPU, "topology/coreId"))
if err == nil {
c.CoreID = lines[0]
}
@@ -87,13 +91,13 @@ func finishCPUInfo(c *CPUInfoStat) error {
// Sockets often come with many physical CPU cores.
// For example a single socket board with two cores each with HT will
// return 4 CPUInfoStat structs on Linux and the "Cores" field set to 1.
func CPUInfo() ([]CPUInfoStat, error) {
func Info() ([]InfoStat, error) {
filename := common.HostProc("cpuinfo")
lines, _ := common.ReadLines(filename)
var ret []CPUInfoStat
var ret []InfoStat
c := CPUInfoStat{CPU: -1, Cores: 1}
c := InfoStat{CPU: -1, Cores: 1}
for _, line := range lines {
fields := strings.Split(line, ":")
if len(fields) < 2 {
@@ -111,13 +115,13 @@ func CPUInfo() ([]CPUInfoStat, error) {
}
ret = append(ret, c)
}
c = CPUInfoStat{Cores: 1}
c = InfoStat{Cores: 1}
t, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return ret, err
}
c.CPU = int32(t)
case "vendor_id":
case "vendorId", "vendor_id":
c.VendorID = value
case "cpu family":
c.Family = value
@@ -163,7 +167,7 @@ func CPUInfo() ([]CPUInfoStat, error) {
return ret, nil
}
func parseStatLine(line string) (*CPUTimesStat, error) {
func parseStatLine(line string) (*TimesStat, error) {
fields := strings.Fields(line)
if strings.HasPrefix(fields[0], "cpu") == false {
@@ -204,7 +208,7 @@ func parseStatLine(line string) (*CPUTimesStat, error) {
return nil, err
}
ct := &CPUTimesStat{
ct := &TimesStat{
CPU: cpu,
User: float64(user) / cpu_tick,
Nice: float64(nice) / cpu_tick,

View File

@@ -7,14 +7,14 @@ import (
"time"
)
func CPUPercent(interval time.Duration, percpu bool) ([]float64, error) {
getAllBusy := func(t CPUTimesStat) (float64, float64) {
func Percent(interval time.Duration, percpu bool) ([]float64, error) {
getAllBusy := func(t TimesStat) (float64, float64) {
busy := t.User + t.System + t.Nice + t.Iowait + t.Irq +
t.Softirq + t.Steal + t.Guest + t.GuestNice + t.Stolen
return busy + t.Idle, busy
}
calculate := func(t1, t2 CPUTimesStat) float64 {
calculate := func(t1, t2 TimesStat) float64 {
t1All, t1Busy := getAllBusy(t1)
t2All, t2Busy := getAllBusy(t2)
@@ -28,7 +28,7 @@ func CPUPercent(interval time.Duration, percpu bool) ([]float64, error) {
}
// Get CPU usage at the start of the interval.
cpuTimes1, err := CPUTimes(percpu)
cpuTimes1, err := Times(percpu)
if err != nil {
return nil, err
}
@@ -38,7 +38,7 @@ func CPUPercent(interval time.Duration, percpu bool) ([]float64, error) {
}
// And at the end of the interval.
cpuTimes2, err := CPUTimes(percpu)
cpuTimes2, err := Times(percpu)
if err != nil {
return nil, err
}

View File

@@ -19,14 +19,14 @@ type Win32_Processor struct {
Manufacturer string
Name string
NumberOfLogicalProcessors uint32
ProcessorId *string
ProcessorID *string
Stepping *string
MaxClockSpeed uint32
}
// TODO: Get percpu
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
var ret []CPUTimesStat
func Times(percpu bool) ([]TimesStat, error) {
var ret []TimesStat
var lpIdleTime common.FILETIME
var lpKernelTime common.FILETIME
@@ -46,7 +46,7 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
kernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime)))
system := (kernel - idle)
ret = append(ret, CPUTimesStat{
ret = append(ret, TimesStat{
Idle: float64(idle),
User: float64(user),
System: float64(system),
@@ -54,8 +54,8 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
return ret, nil
}
func CPUInfo() ([]CPUInfoStat, error) {
var ret []CPUInfoStat
func Info() ([]InfoStat, error) {
var ret []InfoStat
var dst []Win32_Processor
q := wmi.CreateQuery(&dst, "")
err := wmi.Query(q, &dst)
@@ -66,11 +66,11 @@ func CPUInfo() ([]CPUInfoStat, error) {
var procID string
for i, l := range dst {
procID = ""
if l.ProcessorId != nil {
procID = *l.ProcessorId
if l.ProcessorID != nil {
procID = *l.ProcessorID
}
cpu := CPUInfoStat{
cpu := InfoStat{
CPU: int32(i),
Family: fmt.Sprintf("%d", l.Family),
VendorID: l.Manufacturer,
@@ -86,7 +86,7 @@ func CPUInfo() ([]CPUInfoStat, error) {
return ret, nil
}
func CPUPercent(interval time.Duration, percpu bool) ([]float64, error) {
func Percent(interval time.Duration, percpu bool) ([]float64, error) {
var ret []float64
var dst []Win32_Processor
q := wmi.CreateQuery(&dst, "")

View File

@@ -6,17 +6,17 @@ import (
// A HostInfoStat describes the host status.
// This is not in the psutil but it useful.
type HostInfoStat struct {
type InfoStat struct {
Hostname string `json:"hostname"`
Uptime uint64 `json:"uptime"`
BootTime uint64 `json:"boot_time"`
BootTime uint64 `json:"bootTime"`
Procs uint64 `json:"procs"` // number of processes
OS string `json:"os"` // ex: freebsd, linux
Platform string `json:"platform"` // ex: ubuntu, linuxmint
PlatformFamily string `json:"platform_family"` // ex: debian, rhel
PlatformVersion string `json:"platform_version"`
VirtualizationSystem string `json:"virtualization_system"`
VirtualizationRole string `json:"virtualization_role"` // guest or host
PlatformFamily string `json:"platformFamily"` // ex: debian, rhel
PlatformVersion string `json:"platformVersion"`
VirtualizationSystem string `json:"virtualizationSystem"`
VirtualizationRole string `json:"virtualizationRole"` // guest or host
}
@@ -27,7 +27,7 @@ type UserStat struct {
Started int `json:"started"`
}
func (h HostInfoStat) String() string {
func (h InfoStat) String() string {
s, _ := json.Marshal(h)
return string(s)
}

View File

@@ -17,8 +17,11 @@ import (
"github.com/shirou/gopsutil/internal/common"
)
func HostInfo() (*HostInfoStat, error) {
ret := &HostInfoStat{
// from utmpx.h
const USER_PROCESS = 7
func Info() (*InfoStat, error) {
ret := &InfoStat{
OS: runtime.GOOS,
PlatformFamily: "darwin",
}
@@ -28,13 +31,13 @@ func HostInfo() (*HostInfoStat, error) {
ret.Hostname = hostname
}
platform, family, version, err := GetPlatformInformation()
platform, family, version, err := PlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
}
system, role, err := GetVirtualization()
system, role, err := Virtualization()
if err == nil {
ret.VirtualizationSystem = system
ret.VirtualizationRole = role
@@ -103,7 +106,7 @@ func Users() ([]UserStat, error) {
if err != nil {
continue
}
if u.Type != 7 { // skip if not USERPROCESS
if u.Type != USER_PROCESS {
continue
}
user := UserStat{
@@ -119,17 +122,21 @@ func Users() ([]UserStat, error) {
}
func GetPlatformInformation() (string, string, string, error) {
func PlatformInformation() (string, string, string, error) {
platform := ""
family := ""
version := ""
out, err := exec.Command("uname", "-s").Output()
uname, err := exec.LookPath("uname")
if err != nil {
return "", "", "", err
}
out, err := exec.Command(uname, "-s").Output()
if err == nil {
platform = strings.ToLower(strings.TrimSpace(string(out)))
}
out, err = exec.Command("uname", "-r").Output()
out, err = exec.Command(uname, "-r").Output()
if err == nil {
version = strings.ToLower(strings.TrimSpace(string(out)))
}
@@ -137,7 +144,7 @@ func GetPlatformInformation() (string, string, string, error) {
return platform, family, version, nil
}
func GetVirtualization() (string, string, error) {
func Virtualization() (string, string, error) {
system := ""
role := ""

View File

@@ -5,7 +5,7 @@ package host
type Utmpx struct {
User [256]int8
Id [4]int8
ID [4]int8
Line [32]int8
Pid int32
Type int16

View File

@@ -23,8 +23,8 @@ const (
UTHostSize = 16
)
func HostInfo() (*HostInfoStat, error) {
ret := &HostInfoStat{
func Info() (*InfoStat, error) {
ret := &InfoStat{
OS: runtime.GOOS,
PlatformFamily: "freebsd",
}
@@ -34,13 +34,13 @@ func HostInfo() (*HostInfoStat, error) {
ret.Hostname = hostname
}
platform, family, version, err := GetPlatformInformation()
platform, family, version, err := PlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
}
system, role, err := GetVirtualization()
system, role, err := Virtualization()
if err == nil {
ret.VirtualizationSystem = system
ret.VirtualizationRole = role
@@ -101,13 +101,11 @@ func Users() ([]UserStat, error) {
return ret, err
}
u := Utmpx{}
entrySize := int(unsafe.Sizeof(u)) - 3
entrySize = 197 // TODO: why should 197
entrySize := sizeOfUtmpx
count := len(buf) / entrySize
for i := 0; i < count; i++ {
b := buf[i*entrySize : i*entrySize+entrySize]
b := buf[i*sizeOfUtmpx : (i+1)*sizeOfUtmpx]
var u Utmpx
br := bytes.NewReader(b)
err := binary.Read(br, binary.LittleEndian, &u)
@@ -129,17 +127,21 @@ func Users() ([]UserStat, error) {
}
func GetPlatformInformation() (string, string, string, error) {
func PlatformInformation() (string, string, string, error) {
platform := ""
family := ""
version := ""
uname, err := exec.LookPath("uname")
if err != nil {
return "", "", "", err
}
out, err := exec.Command("uname", "-s").Output()
out, err := exec.Command(uname, "-s").Output()
if err == nil {
platform = strings.ToLower(strings.TrimSpace(string(out)))
}
out, err = exec.Command("uname", "-r").Output()
out, err = exec.Command(uname, "-r").Output()
if err == nil {
version = strings.ToLower(strings.TrimSpace(string(out)))
}
@@ -147,7 +149,7 @@ func GetPlatformInformation() (string, string, string, error) {
return platform, family, version, nil
}
func GetVirtualization() (string, string, error) {
func Virtualization() (string, string, error) {
system := ""
role := ""

View File

@@ -0,0 +1,43 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go
package host
const (
sizeofPtr = 0x4
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x4
sizeofLongLong = 0x8
sizeOfUtmpx = 197 // TODO why should 197
)
type (
_C_short int16
_C_int int32
_C_long int32
_C_long_long int64
)
type Utmp struct {
Line [8]int8
Name [16]int8
Host [16]int8
Time int32
}
type Utmpx struct {
Type int16
Tv Timeval
Id [8]int8
Pid int32
User [32]int8
Line [16]int8
Host [125]int8
// X__ut_spare [64]int8
}
type Timeval struct {
Sec [4]byte
Usec [3]byte
}

View File

@@ -9,6 +9,7 @@ const (
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeOfUtmpx = 197 // TODO: why should 197, not 0x118
)
type (
@@ -24,6 +25,7 @@ type Utmp struct {
Host [16]int8
Time int32
}
type Utmpx struct {
Type int16
Tv Timeval
@@ -32,9 +34,10 @@ type Utmpx struct {
User [32]int8
Line [16]int8
Host [125]int8
// Host [128]int8
// X__ut_spare [64]int8
// Host [128]int8
// X__ut_spare [64]int8
}
type Timeval struct {
Sec [4]byte
Usec [3]byte

View File

@@ -14,7 +14,6 @@ import (
"strconv"
"strings"
"time"
"unsafe"
"github.com/shirou/gopsutil/internal/common"
)
@@ -26,8 +25,11 @@ type LSB struct {
Description string
}
func HostInfo() (*HostInfoStat, error) {
ret := &HostInfoStat{
// from utmp.h
const USER_PROCESS = 7
func Info() (*InfoStat, error) {
ret := &InfoStat{
OS: runtime.GOOS,
}
@@ -36,13 +38,13 @@ func HostInfo() (*HostInfoStat, error) {
ret.Hostname = hostname
}
platform, family, version, err := GetPlatformInformation()
platform, family, version, err := PlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
ret.PlatformVersion = version
}
system, role, err := GetVirtualization()
system, role, err := Virtualization()
if err == nil {
ret.VirtualizationSystem = system
ret.VirtualizationRole = role
@@ -105,14 +107,12 @@ func Users() ([]UserStat, error) {
return nil, err
}
u := utmp{}
entrySize := int(unsafe.Sizeof(u))
count := len(buf) / entrySize
count := len(buf) / sizeOfUtmp
ret := make([]UserStat, 0, count)
for i := 0; i < count; i++ {
b := buf[i*entrySize : i*entrySize+entrySize]
b := buf[i*sizeOfUtmp : (i+1)*sizeOfUtmp]
var u utmp
br := bytes.NewReader(b)
@@ -120,11 +120,14 @@ func Users() ([]UserStat, error) {
if err != nil {
continue
}
if u.Type != USER_PROCESS {
continue
}
user := UserStat{
User: common.IntToString(u.User[:]),
Terminal: common.IntToString(u.Line[:]),
Host: common.IntToString(u.Host[:]),
Started: int(u.Tv.TvSec),
Started: int(u.Tv.Sec),
}
ret = append(ret, user)
}
@@ -135,8 +138,8 @@ func Users() ([]UserStat, error) {
func getLSB() (*LSB, error) {
ret := &LSB{}
if common.PathExists("/etc/lsb-release") {
contents, err := common.ReadLines("/etc/lsb-release")
if common.PathExists(common.HostEtc("lsb-release")) {
contents, err := common.ReadLines(common.HostEtc("lsb-release"))
if err != nil {
return ret, err // return empty
}
@@ -157,7 +160,11 @@ func getLSB() (*LSB, error) {
}
}
} else if common.PathExists("/usr/bin/lsb_release") {
out, err := exec.Command("/usr/bin/lsb_release").Output()
lsb_release, err := exec.LookPath("/usr/bin/lsb_release")
if err != nil {
return ret, err
}
out, err := exec.Command(lsb_release).Output()
if err != nil {
return ret, err
}
@@ -183,26 +190,27 @@ func getLSB() (*LSB, error) {
return ret, nil
}
func GetPlatformInformation() (platform string, family string, version string, err error) {
func PlatformInformation() (platform string, family string, version string, err error) {
lsb, err := getLSB()
if err != nil {
lsb = &LSB{}
}
if common.PathExists("/etc/oracle-release") {
if common.PathExists(common.HostEtc("oracle-release")) {
platform = "oracle"
contents, err := common.ReadLines("/etc/oracle-release")
contents, err := common.ReadLines(common.HostEtc("oracle-release"))
if err == nil {
version = getRedhatishVersion(contents)
}
} else if common.PathExists("/etc/enterprise-release") {
} else if common.PathExists(common.HostEtc("enterprise-release")) {
platform = "oracle"
contents, err := common.ReadLines("/etc/enterprise-release")
contents, err := common.ReadLines(common.HostEtc("enterprise-release"))
if err == nil {
version = getRedhatishVersion(contents)
}
} else if common.PathExists("/etc/debian_version") {
} else if common.PathExists(common.HostEtc("debian_version")) {
if lsb.ID == "Ubuntu" {
platform = "ubuntu"
version = lsb.Release
@@ -215,39 +223,39 @@ func GetPlatformInformation() (platform string, family string, version string, e
} else {
platform = "debian"
}
contents, err := common.ReadLines("/etc/debian_version")
contents, err := common.ReadLines(common.HostEtc("debian_version"))
if err == nil {
version = contents[0]
}
}
} else if common.PathExists("/etc/redhat-release") {
contents, err := common.ReadLines("/etc/redhat-release")
} else if common.PathExists(common.HostEtc("redhat-release")) {
contents, err := common.ReadLines(common.HostEtc("redhat-release"))
if err == nil {
version = getRedhatishVersion(contents)
platform = getRedhatishPlatform(contents)
}
} else if common.PathExists("/etc/system-release") {
contents, err := common.ReadLines("/etc/system-release")
} else if common.PathExists(common.HostEtc("system-release")) {
contents, err := common.ReadLines(common.HostEtc("system-release"))
if err == nil {
version = getRedhatishVersion(contents)
platform = getRedhatishPlatform(contents)
}
} else if common.PathExists("/etc/gentoo-release") {
} else if common.PathExists(common.HostEtc("gentoo-release")) {
platform = "gentoo"
contents, err := common.ReadLines("/etc/gentoo-release")
contents, err := common.ReadLines(common.HostEtc("gentoo-release"))
if err == nil {
version = getRedhatishVersion(contents)
}
} else if common.PathExists("/etc/SuSE-release") {
contents, err := common.ReadLines("/etc/SuSE-release")
} else if common.PathExists(common.HostEtc("SuSE-release")) {
contents, err := common.ReadLines(common.HostEtc("SuSE-release"))
if err == nil {
version = getSuseVersion(contents)
platform = getSusePlatform(contents)
}
// TODO: slackware detecion
} else if common.PathExists("/etc/arch-release") {
} else if common.PathExists(common.HostEtc("arch-release")) {
platform = "arch"
// TODO: exherbo detection
version = lsb.Release
} else if lsb.ID == "RedHat" {
platform = "redhat"
version = lsb.Release
@@ -331,7 +339,7 @@ func getSusePlatform(contents []string) string {
return "suse"
}
func GetVirtualization() (string, string, error) {
func Virtualization() (string, string, error) {
var system string
var role string

View File

@@ -11,6 +11,7 @@ const (
sizeofInt = 0x4
sizeofLong = 0x4
sizeofLongLong = 0x8
sizeOfUtmp = 0x180
)
type (
@@ -25,7 +26,7 @@ type utmp struct {
Pad_cgo_0 [2]byte
Pid int32
Line [32]int8
Id [4]int8
ID [4]int8
User [32]int8
Host [256]int8
Exit exit_status
@@ -39,6 +40,6 @@ type exit_status struct {
Exit int16
}
type UtTv struct {
TvSec int32
TvUsec int32
Sec int32
Usec int32
}

View File

@@ -9,6 +9,7 @@ const (
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeOfUtmp = 0x180
)
type (
@@ -28,7 +29,7 @@ type utmp struct {
Host [256]int8
Exit exit_status
Session int32
Tv UtTv
Tv _Ctype_struct___0
Addr_v6 [4]int32
X__glibc_reserved [20]int8
}
@@ -36,7 +37,12 @@ type exit_status struct {
Termination int16
Exit int16
}
type UtTv struct {
TvSec int32
TvUsec int32
type timeval struct {
Sec int64
Usec int64
}
type _Ctype_struct___0 struct {
Sec int32
Usec int32
}

View File

@@ -1,20 +1,21 @@
// +build linux
// +build arm
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_linux.go | sed "s/uint8/int8/g"
package host
const (
sizeofPtr = 0x8
sizeofPtr = 0x4
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLong = 0x4
sizeofLongLong = 0x8
sizeOfUtmp = 0x180
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long int32
_C_long_long int64
)
@@ -28,7 +29,7 @@ type utmp struct {
Host [256]int8
Exit exit_status
Session int32
Tv UtTv
Tv timeval
Addr_v6 [4]int32
X__glibc_reserved [20]int8
}
@@ -36,7 +37,7 @@ type exit_status struct {
Termination int16
Exit int16
}
type UtTv struct {
TvSec int32
TvUsec int32
type timeval struct {
Sec int32
Usec int32
}

View File

@@ -0,0 +1,43 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_linux.go
package host
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeOfUtmp = 0x180
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type utmp struct {
Type int16
Pad_cgo_0 [2]byte
Pid int32
Line [32]int8
Id [4]int8
User [32]int8
Host [256]int8
Exit exit_status
Session int32
Tv timeval
Addr_v6 [4]int32
X__glibc_reserved [20]int8
}
type exit_status struct {
Termination int16
Exit int16
}
type timeval struct {
Sec int64
Usec int64
}

View File

@@ -0,0 +1,43 @@
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_linux.go
package host
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
sizeOfUtmp = 0x180
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type utmp struct {
Type int16
Pad_cgo_0 [2]byte
Pid int32
Line [32]int8
Id [4]int8
User [32]int8
Host [256]int8
Exit exit_status
Session int32
Tv timeval
Addr_v6 [4]int32
X__glibc_reserved [20]int8
}
type exit_status struct {
Termination int16
Exit int16
}
type timeval struct {
Sec int64
Usec int64
}

View File

@@ -28,8 +28,8 @@ type Win32_OperatingSystem struct {
LastBootUpTime time.Time
}
func HostInfo() (*HostInfoStat, error) {
ret := &HostInfoStat{
func Info() (*InfoStat, error) {
ret := &InfoStat{
OS: runtime.GOOS,
}
@@ -38,7 +38,7 @@ func HostInfo() (*HostInfoStat, error) {
ret.Hostname = hostname
}
platform, family, version, err := GetPlatformInformation()
platform, family, version, err := PlatformInformation()
if err == nil {
ret.Platform = platform
ret.PlatformFamily = family
@@ -100,7 +100,7 @@ func Uptime() (uint64, error) {
return uptime(boot), nil
}
func GetPlatformInformation() (platform string, family string, version string, err error) {
func PlatformInformation() (platform string, family string, version string, err error) {
if osInfo == nil {
_, err = GetOSInfo()
if err != nil {

View File

@@ -27,6 +27,7 @@ const (
sizeofInt = C.sizeof_int
sizeofLong = C.sizeof_long
sizeofLongLong = C.sizeof_longlong
sizeOfUtmpx = C.sizeof_struct_utmpx
)
// Basic types

View File

@@ -7,12 +7,11 @@ Input to cgo -godefs.
package host
/*
#define KERNEL
#include <sys/types.h>
#include <utmp.h>
enum {
sizeofPtr = sizeof(void*),
sizeofPtr = sizeof(void*),
};
*/
@@ -26,6 +25,7 @@ const (
sizeofInt = C.sizeof_int
sizeofLong = C.sizeof_long
sizeofLongLong = C.sizeof_longlong
sizeOfUtmp = C.sizeof_struct_utmp
)
// Basic types
@@ -39,7 +39,4 @@ type (
type utmp C.struct_utmp
type exit_status C.struct_exit_status
type UtTv struct {
TvSec int32
TvUsec int32
}
type timeval C.struct_timeval

View File

@@ -1,3 +1,5 @@
package common
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -19,8 +21,6 @@
// 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"

View File

@@ -1,11 +1,11 @@
package common
//
// gopsutil is a port of psutil(http://pythonhosted.org/psutil/).
// This covers these architectures.
// - linux (amd64, arm)
// - freebsd (amd64)
// - windows (amd64)
package common
import (
"bufio"
"errors"
@@ -59,12 +59,11 @@ func (i FakeInvoke) Command(name string, arg ...string) ([]byte, error) {
}
if PathExists(fpath) {
return ioutil.ReadFile(fpath)
} else {
return exec.Command(name, arg...).Output()
}
return exec.Command(name, arg...).Output()
}
var NotImplementedError = errors.New("not implemented yet")
var ErrNotImplementedError = errors.New("not implemented yet")
// ReadLines reads contents from a file and splits them by new lines.
// A convenience wrapper to ReadLinesOffsetN(filename, 0, -1).
@@ -118,6 +117,23 @@ func IntToString(orig []int8) string {
return string(ret[0:size])
}
func UintToString(orig []uint8) string {
ret := make([]byte, len(orig))
size := -1
for i, o := range orig {
if o == 0 {
size = i
break
}
ret[i] = byte(o)
}
if size == -1 {
size = len(orig)
}
return string(ret[0:size])
}
func ByteToString(orig []byte) string {
n := -1
l := -1
@@ -186,7 +202,7 @@ func mustParseFloat64(val string) float64 {
return vv
}
// StringsHas checks the target string slice containes src or not
// StringsHas checks the target string slice contains src or not
func StringsHas(target []string, src string) bool {
for _, t := range target {
if strings.TrimSpace(t) == src {
@@ -206,6 +222,16 @@ func StringsContains(target []string, src string) bool {
return false
}
// IntContains checks the src in any int of the target int slice.
func IntContains(target []int, src int) bool {
for _, t := range target {
if src == t {
return true
}
}
return false
}
// get struct attributes.
// This method is used only for debugging platform dependent code.
func attributes(m interface{}) map[string]reflect.Type {
@@ -236,7 +262,7 @@ func PathExists(filename string) bool {
return false
}
//GetEnv retreives the environment variable key. If it does not exist it returns the default.
//GetEnv retrieves the environment variable key. If it does not exist it returns the default.
func GetEnv(key string, dfault string, combineWith ...string) string {
value := os.Getenv(key)
if value == "" {
@@ -264,3 +290,7 @@ func HostProc(combineWith ...string) string {
func HostSys(combineWith ...string) string {
return GetEnv("HOST_SYS", "/sys", combineWith...)
}
func HostEtc(combineWith ...string) string {
return GetEnv("HOST_ETC", "/etc", combineWith...)
}

View File

@@ -3,6 +3,7 @@
package common
import (
"os"
"os/exec"
"strings"
"syscall"
@@ -10,7 +11,16 @@ import (
)
func DoSysctrl(mib string) ([]string, error) {
out, err := exec.Command("/usr/sbin/sysctl", "-n", mib).Output()
err := os.Setenv("LC_ALL", "C")
if err != nil {
return []string{}, err
}
sysctl, err := exec.LookPath("/usr/sbin/sysctl")
if err != nil {
return []string{}, err
}
out, err := exec.Command(sysctl, "-n", mib).Output()
if err != nil {
return []string{}, err
}

View File

@@ -3,6 +3,7 @@
package common
import (
"os"
"os/exec"
"strings"
"syscall"
@@ -10,7 +11,15 @@ import (
)
func DoSysctrl(mib string) ([]string, error) {
out, err := exec.Command("/sbin/sysctl", "-n", mib).Output()
err := os.Setenv("LC_ALL", "C")
if err != nil {
return []string{}, err
}
sysctl, err := exec.LookPath("/sbin/sysctl")
if err != nil {
return []string{}, err
}
out, err := exec.Command(sysctl, "-n", mib).Output()
if err != nil {
return []string{}, err
}
@@ -22,13 +31,14 @@ func DoSysctrl(mib string) ([]string, error) {
}
func CallSyscall(mib []int32) ([]byte, uint64, error) {
mibptr := unsafe.Pointer(&mib[0])
miblen := uint64(len(mib))
// get required buffer size
length := uint64(0)
_, _, err := syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(unsafe.Pointer(&mib[0])),
uintptr(mibptr),
uintptr(miblen),
0,
uintptr(unsafe.Pointer(&length)),
@@ -46,7 +56,7 @@ func CallSyscall(mib []int32) ([]byte, uint64, error) {
buf := make([]byte, length)
_, _, err = syscall.Syscall6(
syscall.SYS___SYSCTL,
uintptr(unsafe.Pointer(&mib[0])),
uintptr(mibptr),
uintptr(miblen),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(unsafe.Pointer(&length)),

View File

@@ -4,25 +4,51 @@ import (
"encoding/json"
)
// Memory usage statistics. Total, Available and Used contain numbers of bytes
// for human consumption.
//
// The other fields in this struct contain kernel specific values.
type VirtualMemoryStat struct {
Total uint64 `json:"total"`
Available uint64 `json:"available"`
Used uint64 `json:"used"`
UsedPercent float64 `json:"used_percent"`
Free uint64 `json:"free"`
Active uint64 `json:"active"`
Inactive uint64 `json:"inactive"`
Buffers uint64 `json:"buffers"`
Cached uint64 `json:"cached"`
Wired uint64 `json:"wired"`
Shared uint64 `json:"shared"`
// Total amount of RAM on this system
Total uint64 `json:"total"`
// RAM available for programs to allocate
//
// This value is computed from the kernel specific values.
Available uint64 `json:"available"`
// RAM used by programs
//
// This value is computed from the kernel specific values.
Used uint64 `json:"used"`
// Percentage of RAM used by programs
//
// This value is computed from the kernel specific values.
UsedPercent float64 `json:"usedPercent"`
// This is the kernel's notion of free memory; RAM chips whose bits nobody
// cares about the value of right now. For a human consumable number,
// Available is what you really want.
Free uint64 `json:"free"`
// OS X / BSD specific numbers:
// http://www.macyourself.com/2010/02/17/what-is-free-wired-active-and-inactive-system-memory-ram/
Active uint64 `json:"active"`
Inactive uint64 `json:"inactive"`
Wired uint64 `json:"wired"`
// Linux specific numbers
// https://www.centos.org/docs/5/html/5.1/Deployment_Guide/s2-proc-meminfo.html
Buffers uint64 `json:"buffers"`
Cached uint64 `json:"cached"`
}
type SwapMemoryStat struct {
Total uint64 `json:"total"`
Used uint64 `json:"used"`
Free uint64 `json:"free"`
UsedPercent float64 `json:"used_percent"`
UsedPercent float64 `json:"usedPercent"`
Sin uint64 `json:"sin"`
Sout uint64 `json:"sout"`
}

View File

@@ -3,111 +3,27 @@
package mem
import (
"os/exec"
"encoding/binary"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
func getPageSize() (uint64, error) {
out, err := exec.Command("pagesize").Output()
func getHwMemsize() (uint64, error) {
totalString, err := syscall.Sysctl("hw.memsize")
if err != nil {
return 0, err
}
o := strings.TrimSpace(string(out))
p, err := strconv.ParseUint(o, 10, 64)
if err != nil {
return 0, err
}
return p, nil
}
// Runs vm_stat and returns Free and inactive pages
func getVmStat(pagesize uint64, vms *VirtualMemoryStat) error {
out, err := exec.Command("vm_stat").Output()
if err != nil {
return err
}
return parseVmStat(string(out), pagesize, vms)
}
// syscall.sysctl() helpfully assumes the result is a null-terminated string and
// removes the last byte of the result if it's 0 :/
totalString += "\x00"
func parseVmStat(out string, pagesize uint64, vms *VirtualMemoryStat) error {
var err error
total := uint64(binary.LittleEndian.Uint64([]byte(totalString)))
lines := strings.Split(out, "\n")
for _, line := range lines {
fields := strings.Split(line, ":")
if len(fields) < 2 {
continue
}
key := strings.TrimSpace(fields[0])
value := strings.Trim(fields[1], " .")
switch key {
case "Pages free":
free, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Free = free * pagesize
case "Pages inactive":
inactive, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Cached += inactive * pagesize
vms.Inactive = inactive * pagesize
case "Pages active":
active, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Active = active * pagesize
case "Pages wired down":
wired, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Wired = wired * pagesize
case "Pages purgeable":
purgeable, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Cached += purgeable * pagesize
}
}
return err
}
// VirtualMemory returns VirtualmemoryStat.
func VirtualMemory() (*VirtualMemoryStat, error) {
ret := &VirtualMemoryStat{}
p, err := getPageSize()
if err != nil {
return nil, err
}
t, err := common.DoSysctrl("hw.memsize")
if err != nil {
return nil, err
}
total, err := strconv.ParseUint(t[0], 10, 64)
if err != nil {
return nil, err
}
err = getVmStat(p, ret)
if err != nil {
return nil, err
}
ret.Available = ret.Free + ret.Cached
ret.Total = total
ret.Used = ret.Total - ret.Free
ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0
return ret, nil
return total, nil
}
// SwapMemory returns swapinfo.

View File

@@ -0,0 +1,53 @@
// +build darwin
// +build cgo
package mem
/*
#include <mach/mach_host.h>
*/
import "C"
import (
"fmt"
"syscall"
"unsafe"
)
// VirtualMemory returns VirtualmemoryStat.
func VirtualMemory() (*VirtualMemoryStat, error) {
count := C.mach_msg_type_number_t(C.HOST_VM_INFO_COUNT)
var vmstat C.vm_statistics_data_t
status := C.host_statistics(C.host_t(C.mach_host_self()),
C.HOST_VM_INFO,
C.host_info_t(unsafe.Pointer(&vmstat)),
&count)
if status != C.KERN_SUCCESS {
return nil, fmt.Errorf("host_statistics error=%d", status)
}
pageSize := uint64(syscall.Getpagesize())
total, err := getHwMemsize()
if err != nil {
return nil, err
}
totalCount := C.natural_t(total / pageSize)
availableCount := vmstat.inactive_count + vmstat.free_count
usedPercent := 100 * float64(totalCount-availableCount) / float64(totalCount)
usedCount := totalCount - availableCount
return &VirtualMemoryStat{
Total: total,
Available: pageSize * uint64(availableCount),
Used: pageSize * uint64(usedCount),
UsedPercent: usedPercent,
Free: pageSize * uint64(vmstat.free_count),
Active: pageSize * uint64(vmstat.active_count),
Inactive: pageSize * uint64(vmstat.inactive_count),
Wired: pageSize * uint64(vmstat.wire_count),
}, nil
}

View File

@@ -0,0 +1,88 @@
// +build darwin
// +build !cgo
package mem
import (
"os/exec"
"strconv"
"strings"
"syscall"
)
// Runs vm_stat and returns Free and inactive pages
func getVMStat(vms *VirtualMemoryStat) error {
vm_stat, err := exec.LookPath("vm_stat")
if err != nil {
return err
}
out, err := exec.Command(vm_stat).Output()
if err != nil {
return err
}
return parseVMStat(string(out), vms)
}
func parseVMStat(out string, vms *VirtualMemoryStat) error {
var err error
lines := strings.Split(out, "\n")
pagesize := uint64(syscall.Getpagesize())
for _, line := range lines {
fields := strings.Split(line, ":")
if len(fields) < 2 {
continue
}
key := strings.TrimSpace(fields[0])
value := strings.Trim(fields[1], " .")
switch key {
case "Pages free":
free, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Free = free * pagesize
case "Pages inactive":
inactive, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Inactive = inactive * pagesize
case "Pages active":
active, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Active = active * pagesize
case "Pages wired down":
wired, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
vms.Wired = wired * pagesize
}
}
return err
}
// VirtualMemory returns VirtualmemoryStat.
func VirtualMemory() (*VirtualMemoryStat, error) {
ret := &VirtualMemoryStat{}
total, err := getHwMemsize()
if err != nil {
return nil, err
}
err = getVMStat(ret)
if err != nil {
return nil, err
}
ret.Available = ret.Free + ret.Inactive
ret.Total = total
ret.Used = ret.Total - ret.Available
ret.UsedPercent = 100 * float64(ret.Used) / float64(ret.Total)
return ret, nil
}

View File

@@ -3,10 +3,11 @@
package mem
import (
"errors"
"os/exec"
"strconv"
"strings"
"errors"
"github.com/shirou/gopsutil/internal/common"
)
@@ -78,8 +79,8 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
}
ret.Available = ret.Inactive + ret.Cached + ret.Free
ret.Used = ret.Active + ret.Wired + ret.Cached
ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0
ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
return ret, nil
}
@@ -87,7 +88,12 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
// Return swapinfo
// FreeBSD can have multiple swap devices. but use only first device
func SwapMemory() (*SwapMemoryStat, error) {
out, err := exec.Command("swapinfo").Output()
swapinfo, err := exec.LookPath("swapinfo")
if err != nil {
return nil, err
}
out, err := exec.Command(swapinfo).Output()
if err != nil {
return nil, err
}

View File

@@ -51,7 +51,7 @@ func VirtualMemory() (*VirtualMemoryStat, error) {
if !memavail {
ret.Available = ret.Free + ret.Buffers + ret.Cached
}
ret.Used = ret.Total - ret.Free
ret.Used = ret.Total - ret.Available
ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0
return ret, nil

View File

@@ -13,7 +13,7 @@ var (
procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx")
)
type MEMORYSTATUSEX struct {
type memoryStatusEx struct {
cbSize uint32
dwMemoryLoad uint32
ullTotalPhys uint64 // in bytes
@@ -26,7 +26,7 @@ type MEMORYSTATUSEX struct {
}
func VirtualMemory() (*VirtualMemoryStat, error) {
var memInfo MEMORYSTATUSEX
var memInfo memoryStatusEx
memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
if mem == 0 {

View File

@@ -17,12 +17,12 @@ func init() {
invoke = common.Invoke{}
}
type NetIOCountersStat struct {
type IOCountersStat struct {
Name string `json:"name"` // interface name
BytesSent uint64 `json:"bytes_sent"` // number of bytes sent
BytesRecv uint64 `json:"bytes_recv"` // number of bytes received
PacketsSent uint64 `json:"packets_sent"` // number of packets sent
PacketsRecv uint64 `json:"packets_recv"` // number of packets received
BytesSent uint64 `json:"bytesSent"` // number of bytes sent
BytesRecv uint64 `json:"bytesRecv"` // number of bytes received
PacketsSent uint64 `json:"packetsSent"` // number of packets sent
PacketsRecv uint64 `json:"packetsRecv"` // number of packets received
Errin uint64 `json:"errin"` // total number of errors while receiving
Errout uint64 `json:"errout"` // total number of errors while sending
Dropin uint64 `json:"dropin"` // total number of incoming packets which were dropped
@@ -35,7 +35,7 @@ type Addr struct {
Port uint32 `json:"port"`
}
type NetConnectionStat struct {
type ConnectionStat struct {
Fd uint32 `json:"fd"`
Family uint32 `json:"family"`
Type uint32 `json:"type"`
@@ -46,27 +46,27 @@ type NetConnectionStat struct {
}
// System wide stats about different network protocols
type NetProtoCountersStat struct {
type ProtoCountersStat struct {
Protocol string `json:"protocol"`
Stats map[string]int64 `json:"stats"`
}
// NetInterfaceAddr is designed for represent interface addresses
type NetInterfaceAddr struct {
type InterfaceAddr struct {
Addr string `json:"addr"`
}
type NetInterfaceStat struct {
MTU int `json:"mtu"` // maximum transmission unit
Name string `json:"name"` // e.g., "en0", "lo0", "eth0.100"
HardwareAddr string `json:"hardwareaddr"` // IEEE MAC-48, EUI-48 and EUI-64 form
Flags []string `json:"flags"` // e.g., FlagUp, FlagLoopback, FlagMulticast
Addrs []NetInterfaceAddr `json:"addrs"`
type InterfaceStat struct {
MTU int `json:"mtu"` // maximum transmission unit
Name string `json:"name"` // e.g., "en0", "lo0", "eth0.100"
HardwareAddr string `json:"hardwareaddr"` // IEEE MAC-48, EUI-48 and EUI-64 form
Flags []string `json:"flags"` // e.g., FlagUp, FlagLoopback, FlagMulticast
Addrs []InterfaceAddr `json:"addrs"`
}
type NetFilterStat struct {
ConnTrackCount int64 `json:"conntrack_count"`
ConnTrackMax int64 `json:"conntrack_max"`
type FilterStat struct {
ConnTrackCount int64 `json:"conntrackCount"`
ConnTrackMax int64 `json:"conntrackMax"`
}
var constMap = map[string]int{
@@ -76,17 +76,17 @@ var constMap = map[string]int{
"IPv6": syscall.AF_INET6,
}
func (n NetIOCountersStat) String() string {
func (n IOCountersStat) String() string {
s, _ := json.Marshal(n)
return string(s)
}
func (n NetConnectionStat) String() string {
func (n ConnectionStat) String() string {
s, _ := json.Marshal(n)
return string(s)
}
func (n NetProtoCountersStat) String() string {
func (n ProtoCountersStat) String() string {
s, _ := json.Marshal(n)
return string(s)
}
@@ -96,22 +96,22 @@ func (a Addr) String() string {
return string(s)
}
func (n NetInterfaceStat) String() string {
func (n InterfaceStat) String() string {
s, _ := json.Marshal(n)
return string(s)
}
func (n NetInterfaceAddr) String() string {
func (n InterfaceAddr) String() string {
s, _ := json.Marshal(n)
return string(s)
}
func NetInterfaces() ([]NetInterfaceStat, error) {
func Interfaces() ([]InterfaceStat, error) {
is, err := net.Interfaces()
if err != nil {
return nil, err
}
ret := make([]NetInterfaceStat, 0, len(is))
ret := make([]InterfaceStat, 0, len(is))
for _, ifi := range is {
var flags []string
@@ -131,7 +131,7 @@ func NetInterfaces() ([]NetInterfaceStat, error) {
flags = append(flags, "multicast")
}
r := NetInterfaceStat{
r := InterfaceStat{
Name: ifi.Name,
MTU: ifi.MTU,
HardwareAddr: ifi.HardwareAddr.String(),
@@ -139,9 +139,9 @@ func NetInterfaces() ([]NetInterfaceStat, error) {
}
addrs, err := ifi.Addrs()
if err == nil {
r.Addrs = make([]NetInterfaceAddr, 0, len(addrs))
r.Addrs = make([]InterfaceAddr, 0, len(addrs))
for _, addr := range addrs {
r.Addrs = append(r.Addrs, NetInterfaceAddr{
r.Addrs = append(r.Addrs, InterfaceAddr{
Addr: addr.String(),
})
}
@@ -153,8 +153,8 @@ func NetInterfaces() ([]NetInterfaceStat, error) {
return ret, nil
}
func getNetIOCountersAll(n []NetIOCountersStat) ([]NetIOCountersStat, error) {
r := NetIOCountersStat{
func getIOCountersAll(n []IOCountersStat) ([]IOCountersStat, error) {
r := IOCountersStat{
Name: "all",
}
for _, nic := range n {
@@ -168,38 +168,38 @@ func getNetIOCountersAll(n []NetIOCountersStat) ([]NetIOCountersStat, error) {
r.Dropout += nic.Dropout
}
return []NetIOCountersStat{r}, nil
return []IOCountersStat{r}, nil
}
func parseNetLine(line string) (NetConnectionStat, error) {
func parseNetLine(line string) (ConnectionStat, error) {
f := strings.Fields(line)
if len(f) < 9 {
return NetConnectionStat{}, fmt.Errorf("wrong line,%s", line)
return ConnectionStat{}, fmt.Errorf("wrong line,%s", line)
}
pid, err := strconv.Atoi(f[1])
if err != nil {
return NetConnectionStat{}, err
return ConnectionStat{}, err
}
fd, err := strconv.Atoi(strings.Trim(f[3], "u"))
if err != nil {
return NetConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3])
return ConnectionStat{}, fmt.Errorf("unknown fd, %s", f[3])
}
netFamily, ok := constMap[f[4]]
if !ok {
return NetConnectionStat{}, fmt.Errorf("unknown family, %s", f[4])
return ConnectionStat{}, fmt.Errorf("unknown family, %s", f[4])
}
netType, ok := constMap[f[7]]
if !ok {
return NetConnectionStat{}, fmt.Errorf("unknown type, %s", f[7])
return ConnectionStat{}, fmt.Errorf("unknown type, %s", f[7])
}
laddr, raddr, err := parseNetAddr(f[8])
if err != nil {
return NetConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8])
return ConnectionStat{}, fmt.Errorf("failed to parse netaddr, %s", f[8])
}
n := NetConnectionStat{
n := ConnectionStat{
Fd: uint32(fd),
Family: uint32(netFamily),
Type: uint32(netType),

View File

@@ -16,14 +16,18 @@ import (
// lo0 16384 <Link#1> 869107 0 169411755 869107 0 169411755 0 0
// lo0 16384 ::1/128 ::1 869107 - 169411755 869107 - 169411755 - -
// lo0 16384 127 127.0.0.1 869107 - 169411755 869107 - 169411755 - -
func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
out, err := exec.Command("/usr/sbin/netstat", "-ibdnW").Output()
func IOCounters(pernic bool) ([]IOCountersStat, error) {
netstat, err := exec.LookPath("/usr/sbin/netstat")
if err != nil {
return nil, err
}
out, err := exec.Command(netstat, "-ibdnW").Output()
if err != nil {
return nil, err
}
lines := strings.Split(string(out), "\n")
ret := make([]NetIOCountersStat, 0, len(lines)-1)
ret := make([]IOCountersStat, 0, len(lines)-1)
exists := make([]string, 0, len(ret))
for _, line := range lines {
@@ -70,7 +74,7 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
parsed = append(parsed, t)
}
n := NetIOCountersStat{
n := IOCountersStat{
Name: values[0],
PacketsRecv: parsed[0],
Errin: parsed[1],
@@ -86,16 +90,25 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
}
if pernic == false {
return getNetIOCountersAll(ret)
return getIOCountersAll(ret)
}
return ret, nil
}
// NetIOCountersByFile is an method which is added just a compatibility for linux.
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
return IOCounters(pernic)
}
func FilterCounters() ([]FilterStat, error) {
return nil, errors.New("NetFilterCounters not implemented for darwin")
}
// NetProtoCounters returns network statistics for the entire system
// If protocols is empty then all protocols are returned, otherwise
// just the protocols in the list are returned.
// Not Implemented for Darwin
func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
return nil, errors.New("NetProtoCounters not implemented for darwin")
}

View File

@@ -11,14 +11,18 @@ import (
"github.com/shirou/gopsutil/internal/common"
)
func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
out, err := exec.Command("/usr/bin/netstat", "-ibdnW").Output()
func IOCounters(pernic bool) ([]IOCountersStat, error) {
netstat, err := exec.LookPath("/usr/bin/netstat")
if err != nil {
return nil, err
}
out, err := exec.Command(netstat, "-ibdnW").Output()
if err != nil {
return nil, err
}
lines := strings.Split(string(out), "\n")
ret := make([]NetIOCountersStat, 0, len(lines)-1)
ret := make([]IOCountersStat, 0, len(lines)-1)
exists := make([]string, 0, len(ret))
for _, line := range lines {
@@ -65,7 +69,7 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
parsed = append(parsed, t)
}
n := NetIOCountersStat{
n := IOCountersStat{
Name: values[0],
PacketsRecv: parsed[0],
Errin: parsed[1],
@@ -80,16 +84,25 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
}
if pernic == false {
return getNetIOCountersAll(ret)
return getIOCountersAll(ret)
}
return ret, nil
}
// NetIOCountersByFile is an method which is added just a compatibility for linux.
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
return IOCounters(pernic)
}
func FilterCounters() ([]FilterStat, error) {
return nil, errors.New("NetFilterCounters not implemented for freebsd")
}
// NetProtoCounters returns network statistics for the entire system
// If protocols is empty then all protocols are returned, otherwise
// just the protocols in the list are returned.
// Not Implemented for FreeBSD
func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
return nil, errors.New("NetProtoCounters not implemented for freebsd")
}

View File

@@ -3,9 +3,15 @@
package net
import (
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"net"
"os"
"strconv"
"strings"
"syscall"
"github.com/shirou/gopsutil/internal/common"
)
@@ -15,8 +21,12 @@ import (
// return only sum of all information (which name is 'all'). If true,
// every network interface installed on the system is returned
// separately.
func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
func IOCounters(pernic bool) ([]IOCountersStat, error) {
filename := common.HostProc("net/dev")
return IOCountersByFile(pernic, filename)
}
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
lines, err := common.ReadLines(filename)
if err != nil {
return nil, err
@@ -24,7 +34,7 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
statlen := len(lines) - 1
ret := make([]NetIOCountersStat, 0, statlen)
ret := make([]IOCountersStat, 0, statlen)
for _, line := range lines[2:] {
parts := strings.SplitN(line, ":", 2)
@@ -70,7 +80,7 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
return ret, err
}
nic := NetIOCountersStat{
nic := IOCountersStat{
Name: interfaceName,
BytesRecv: bytesRecv,
PacketsRecv: packetsRecv,
@@ -85,7 +95,7 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
}
if pernic == false {
return getNetIOCountersAll(ret)
return getIOCountersAll(ret)
}
return ret, nil
@@ -105,12 +115,12 @@ var netProtocols = []string{
// just the protocols in the list are returned.
// Available protocols:
// ip,icmp,icmpmsg,tcp,udp,udplite
func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
if len(protocols) == 0 {
protocols = netProtocols
}
stats := make([]NetProtoCountersStat, 0, len(protocols))
stats := make([]ProtoCountersStat, 0, len(protocols))
protos := make(map[string]bool, len(protocols))
for _, p := range protocols {
protos[p] = true
@@ -145,7 +155,7 @@ func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
if len(statNames) != len(statValues) {
return nil, errors.New(filename + " is not fomatted correctly, expected same number of columns.")
}
stat := NetProtoCountersStat{
stat := ProtoCountersStat{
Protocol: proto,
Stats: make(map[string]int64, len(statNames)),
}
@@ -164,23 +174,23 @@ func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
// NetFilterCounters returns iptables conntrack statistics
// the currently in use conntrack count and the max.
// If the file does not exist or is invalid it will return nil.
func NetFilterCounters() ([]NetFilterStat, error) {
countfile := common.HostProc("sys/net/netfilter/nf_conntrack_count")
maxfile := common.HostProc("sys/net/netfilter/nf_conntrack_max")
func FilterCounters() ([]FilterStat, error) {
countfile := common.HostProc("sys/net/netfilter/nf_conntrackCount")
maxfile := common.HostProc("sys/net/netfilter/nf_conntrackMax")
count, err := common.ReadInts(countfile)
if err != nil {
return nil, err
}
stats := make([]NetFilterStat, 0, 1)
stats := make([]FilterStat, 0, 1)
max, err := common.ReadInts(maxfile)
if err != nil {
return nil, err
}
payload := NetFilterStat{
payload := FilterStat{
ConnTrackCount: count[0],
ConnTrackMax: max[0],
}
@@ -188,3 +198,423 @@ func NetFilterCounters() ([]NetFilterStat, error) {
stats = append(stats, payload)
return stats, nil
}
// http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
var TCPStatuses = map[string]string{
"01": "ESTABLISHED",
"02": "SYN_SENT",
"03": "SYN_RECV",
"04": "FIN_WAIT1",
"05": "FIN_WAIT2",
"06": "TIME_WAIT",
"07": "CLOSE",
"08": "CLOSE_WAIT",
"09": "LAST_ACK",
"0A": "LISTEN",
"0B": "CLOSING",
}
type netConnectionKindType struct {
family uint32
sockType uint32
filename string
}
var kindTCP4 = netConnectionKindType{
family: syscall.AF_INET,
sockType: syscall.SOCK_STREAM,
filename: "tcp",
}
var kindTCP6 = netConnectionKindType{
family: syscall.AF_INET6,
sockType: syscall.SOCK_STREAM,
filename: "tcp6",
}
var kindUDP4 = netConnectionKindType{
family: syscall.AF_INET,
sockType: syscall.SOCK_DGRAM,
filename: "udp",
}
var kindUDP6 = netConnectionKindType{
family: syscall.AF_INET6,
sockType: syscall.SOCK_DGRAM,
filename: "udp6",
}
var kindUNIX = netConnectionKindType{
family: syscall.AF_UNIX,
filename: "unix",
}
var netConnectionKindMap = map[string][]netConnectionKindType{
"all": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6, kindUNIX},
"tcp": []netConnectionKindType{kindTCP4, kindTCP6},
"tcp4": []netConnectionKindType{kindTCP4},
"tcp6": []netConnectionKindType{kindTCP6},
"udp": []netConnectionKindType{kindUDP4, kindUDP6},
"udp4": []netConnectionKindType{kindUDP4},
"udp6": []netConnectionKindType{kindUDP6},
"unix": []netConnectionKindType{kindUNIX},
"inet": []netConnectionKindType{kindTCP4, kindTCP6, kindUDP4, kindUDP6},
"inet4": []netConnectionKindType{kindTCP4, kindUDP4},
"inet6": []netConnectionKindType{kindTCP6, kindUDP6},
}
type inodeMap struct {
pid int32
fd uint32
}
type connTmp struct {
fd uint32
family uint32
sockType uint32
laddr Addr
raddr Addr
status string
pid int32
boundPid int32
path string
}
// Return a list of network connections opened.
func Connections(kind string) ([]ConnectionStat, error) {
return ConnectionsPid(kind, 0)
}
// Return a list of network connections opened by a process.
func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
tmap, ok := netConnectionKindMap[kind]
if !ok {
return nil, fmt.Errorf("invalid kind, %s", kind)
}
root := common.HostProc()
var err error
var inodes map[string][]inodeMap
if pid == 0 {
inodes, err = getProcInodesAll(root)
} else {
inodes, err = getProcInodes(root, pid)
if len(inodes) == 0 {
// no connection for the pid
return []ConnectionStat{}, nil
}
}
if err != nil {
return nil, fmt.Errorf("cound not get pid(s), %d", pid)
}
dupCheckMap := make(map[string]bool)
var ret []ConnectionStat
for _, t := range tmap {
var path string
var ls []connTmp
path = fmt.Sprintf("%s/net/%s", root, t.filename)
switch t.family {
case syscall.AF_INET:
fallthrough
case syscall.AF_INET6:
ls, err = processInet(path, t, inodes, pid)
case syscall.AF_UNIX:
ls, err = processUnix(path, t, inodes, pid)
}
if err != nil {
return nil, err
}
for _, c := range ls {
conn := ConnectionStat{
Fd: c.fd,
Family: c.family,
Type: c.sockType,
Laddr: c.laddr,
Raddr: c.raddr,
Status: c.status,
Pid: c.pid,
}
if c.pid == 0 {
conn.Pid = c.boundPid
} else {
conn.Pid = c.pid
}
// check duplicate using JSON format
json := conn.String()
_, exists := dupCheckMap[json]
if !exists {
ret = append(ret, conn)
dupCheckMap[json] = true
}
}
}
return ret, nil
}
// getProcInodes returnes fd of the pid.
func getProcInodes(root string, pid int32) (map[string][]inodeMap, error) {
ret := make(map[string][]inodeMap)
dir := fmt.Sprintf("%s/%d/fd", root, pid)
files, err := ioutil.ReadDir(dir)
if err != nil {
return ret, nil
}
for _, fd := range files {
inodePath := fmt.Sprintf("%s/%d/fd/%s", root, pid, fd.Name())
inode, err := os.Readlink(inodePath)
if err != nil {
continue
}
if !strings.HasPrefix(inode, "socket:[") {
continue
}
// the process is using a socket
l := len(inode)
inode = inode[8 : l-1]
_, ok := ret[inode]
if !ok {
ret[inode] = make([]inodeMap, 0)
}
fd, err := strconv.Atoi(fd.Name())
if err != nil {
continue
}
i := inodeMap{
pid: pid,
fd: uint32(fd),
}
ret[inode] = append(ret[inode], i)
}
return ret, nil
}
// Pids retunres all pids.
// Note: this is a copy of process_linux.Pids()
// FIXME: Import process occures import cycle.
// move to common made other platform breaking. Need consider.
func Pids() ([]int32, error) {
var ret []int32
d, err := os.Open(common.HostProc())
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 getProcInodesAll(root string) (map[string][]inodeMap, error) {
pids, err := Pids()
if err != nil {
return nil, err
}
ret := make(map[string][]inodeMap)
for _, pid := range pids {
t, err := getProcInodes(root, pid)
if err != nil {
return ret, err
}
if len(t) == 0 {
continue
}
// TODO: update ret.
ret = updateMap(ret, t)
}
return ret, nil
}
// decodeAddress decode addresse represents addr in proc/net/*
// ex:
// "0500000A:0016" -> "10.0.0.5", 22
// "0085002452100113070057A13F025401:0035" -> "2400:8500:1301:1052:a157:7:154:23f", 53
func decodeAddress(family uint32, src string) (Addr, error) {
t := strings.Split(src, ":")
if len(t) != 2 {
return Addr{}, fmt.Errorf("does not contain port, %s", src)
}
addr := t[0]
port, err := strconv.ParseInt("0x"+t[1], 0, 64)
if err != nil {
return Addr{}, fmt.Errorf("invalid port, %s", src)
}
decoded, err := hex.DecodeString(addr)
if err != nil {
return Addr{}, fmt.Errorf("decode error, %s", err)
}
var ip net.IP
// Assumes this is little_endian
if family == syscall.AF_INET {
ip = net.IP(Reverse(decoded))
} else { // IPv6
ip, err = parseIPv6HexString(decoded)
if err != nil {
return Addr{}, err
}
}
return Addr{
IP: ip.String(),
Port: uint32(port),
}, nil
}
// Reverse reverses array of bytes.
func Reverse(s []byte) []byte {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return s
}
// parseIPv6HexString parse array of bytes to IPv6 string
func parseIPv6HexString(src []byte) (net.IP, error) {
if len(src) != 16 {
return nil, fmt.Errorf("invalid IPv6 string")
}
buf := make([]byte, 0, 16)
for i := 0; i < len(src); i += 4 {
r := Reverse(src[i : i+4])
buf = append(buf, r...)
}
return net.IP(buf), nil
}
func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
if strings.HasSuffix(file, "6") && !common.PathExists(file) {
// IPv6 not supported, return empty.
return []connTmp{}, nil
}
lines, err := common.ReadLines(file)
if err != nil {
return nil, err
}
var ret []connTmp
// skip first line
for _, line := range lines[1:] {
l := strings.Fields(line)
if len(l) < 10 {
continue
}
laddr := l[1]
raddr := l[2]
status := l[3]
inode := l[9]
pid := int32(0)
fd := uint32(0)
i, exists := inodes[inode]
if exists {
pid = i[0].pid
fd = i[0].fd
}
if filterPid > 0 && filterPid != pid {
continue
}
if kind.sockType == syscall.SOCK_STREAM {
status = TCPStatuses[status]
} else {
status = "NONE"
}
la, err := decodeAddress(kind.family, laddr)
if err != nil {
continue
}
ra, err := decodeAddress(kind.family, raddr)
if err != nil {
continue
}
ret = append(ret, connTmp{
fd: fd,
family: kind.family,
sockType: kind.sockType,
laddr: la,
raddr: ra,
status: status,
pid: pid,
})
}
return ret, nil
}
func processUnix(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) {
lines, err := common.ReadLines(file)
if err != nil {
return nil, err
}
var ret []connTmp
// skip first line
for _, line := range lines[1:] {
tokens := strings.Fields(line)
if len(tokens) < 6 {
continue
}
st, err := strconv.Atoi(tokens[4])
if err != nil {
return nil, err
}
inode := tokens[6]
var pairs []inodeMap
pairs, exists := inodes[inode]
if !exists {
pairs = []inodeMap{
inodeMap{},
}
}
for _, pair := range pairs {
if filterPid > 0 && filterPid != pair.pid {
continue
}
var path string
if len(tokens) == 8 {
path = tokens[len(tokens)-1]
}
ret = append(ret, connTmp{
fd: pair.fd,
family: kind.family,
sockType: uint32(st),
laddr: Addr{
IP: path,
},
pid: pair.pid,
status: "NONE",
path: path,
})
}
}
return ret, nil
}
func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap {
for key, value := range add {
a, exists := src[key]
if !exists {
src[key] = value
continue
}
src[key] = append(a, value...)
}
return src
}

View File

@@ -1,4 +1,4 @@
// +build linux freebsd darwin
// +build freebsd darwin
package net
@@ -9,13 +9,13 @@ import (
)
// Return a list of network connections opened.
func NetConnections(kind string) ([]NetConnectionStat, error) {
return NetConnectionsPid(kind, 0)
func Connections(kind string) ([]ConnectionStat, error) {
return ConnectionsPid(kind, 0)
}
// Return a list of network connections opened by a process.
func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) {
var ret []NetConnectionStat
func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) {
var ret []ConnectionStat
args := []string{"-i"}
switch strings.ToLower(kind) {
@@ -44,7 +44,7 @@ func NetConnectionsPid(kind string, pid int32) ([]NetConnectionStat, error) {
case "udp6":
args = append(args, "6udp")
case "unix":
return ret, common.NotImplementedError
return ret, common.ErrNotImplementedError
}
r, err := common.CallLsof(invoke, pid, args...)

View File

@@ -14,8 +14,8 @@ import (
var (
modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll")
procGetExtendedTcpTable = modiphlpapi.NewProc("GetExtendedTcpTable")
procGetExtendedUdpTable = modiphlpapi.NewProc("GetExtendedUdpTable")
procGetExtendedTCPTable = modiphlpapi.NewProc("GetExtendedTcpTable")
procGetExtendedUDPTable = modiphlpapi.NewProc("GetExtendedUdpTable")
)
const (
@@ -30,7 +30,7 @@ const (
TCPTableOwnerModuleAll
)
func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
func IOCounters(pernic bool) ([]IOCountersStat, error) {
ifs, err := net.Interfaces()
if err != nil {
return nil, err
@@ -40,13 +40,13 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
if err != nil {
return nil, err
}
var ret []NetIOCountersStat
var ret []IOCountersStat
for _, ifi := range ifs {
name := ifi.Name
for ; ai != nil; ai = ai.Next {
name = common.BytePtrToString(&ai.Description[0])
c := NetIOCountersStat{
c := IOCountersStat{
Name: name,
}
@@ -69,16 +69,21 @@ func NetIOCounters(pernic bool) ([]NetIOCountersStat, error) {
}
if pernic == false {
return getNetIOCountersAll(ret)
return getIOCountersAll(ret)
}
return ret, nil
}
// Return a list of network connections opened by a process
func NetConnections(kind string) ([]NetConnectionStat, error) {
var ret []NetConnectionStat
// NetIOCountersByFile is an method which is added just a compatibility for linux.
func IOCountersByFile(pernic bool, filename string) ([]IOCountersStat, error) {
return IOCounters(pernic)
}
return ret, common.NotImplementedError
// Return a list of network connections opened by a process
func Connections(kind string) ([]ConnectionStat, error) {
var ret []ConnectionStat
return ret, common.ErrNotImplementedError
}
// borrowed from src/pkg/net/interface_windows.go
@@ -98,10 +103,14 @@ func getAdapterList() (*syscall.IpAdapterInfo, error) {
return a, nil
}
func FilterCounters() ([]FilterStat, error) {
return nil, errors.New("NetFilterCounters not implemented for windows")
}
// NetProtoCounters returns network statistics for the entire system
// If protocols is empty then all protocols are returned, otherwise
// just the protocols in the list are returned.
// Not Implemented for Windows
func NetProtoCounters(protocols []string) ([]NetProtoCountersStat, error) {
func ProtoCounters(protocols []string) ([]ProtoCountersStat, error) {
return nil, errors.New("NetProtoCounters not implemented for windows")
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/internal/common"
"github.com/shirou/gopsutil/mem"
)
var invoke common.Invoker
@@ -19,13 +20,14 @@ type Process struct {
Pid int32 `json:"pid"`
name string
status string
parent int32
numCtxSwitches *NumCtxSwitchesStat
uids []int32
gids []int32
numThreads int32
memInfo *MemoryInfoStat
lastCPUTimes *cpu.CPUTimesStat
lastCPUTimes *cpu.TimesStat
lastCPUTime time.Time
}
@@ -47,10 +49,10 @@ type RlimitStat struct {
}
type IOCountersStat struct {
ReadCount uint64 `json:"read_count"`
WriteCount uint64 `json:"write_count"`
ReadBytes uint64 `json:"read_bytes"`
WriteBytes uint64 `json:"write_bytes"`
ReadCount uint64 `json:"readCount"`
WriteCount uint64 `json:"writeCount"`
ReadBytes uint64 `json:"readBytes"`
WriteBytes uint64 `json:"writeBytes"`
}
type NumCtxSwitchesStat struct {
@@ -105,45 +107,61 @@ func PidExists(pid int32) (bool, error) {
// 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()
func (p *Process) Percent(interval time.Duration) (float64, error) {
cpuTimes, err := p.Times()
if err != nil {
return 0, err
}
now := time.Now()
if interval > 0 {
p.lastCPUTimes = cpuTimes
p.lastCPUTime = time.Now()
p.lastCPUTime = now
time.Sleep(interval)
cpuTimes, err = p.CPUTimes()
cpuTimes, err = p.Times()
now = time.Now()
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()
p.lastCPUTimes = cpuTimes
p.lastCPUTime = now
return 0, nil
}
}
delta := (time.Now().Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
ret := calculate(p.lastCPUTimes, cpuTimes, float64(delta))
numcpu := runtime.NumCPU()
delta := (now.Sub(p.lastCPUTime).Seconds()) * float64(numcpu)
ret := calculatePercent(p.lastCPUTimes, cpuTimes, delta, numcpu)
p.lastCPUTimes = cpuTimes
p.lastCPUTime = time.Now()
p.lastCPUTime = now
return ret, nil
}
func calculatePercent(t1, t2 *cpu.TimesStat, delta float64, numcpu int) float64 {
if delta == 0 {
return 0
}
delta_proc := t2.Total() - t1.Total()
overall_percent := ((delta_proc / delta) * 100) * float64(numcpu)
return overall_percent
}
// MemoryPercent returns how many percent of the total RAM this process uses
func (p *Process) MemoryPercent() (float32, error) {
machineMemory, err := mem.VirtualMemory()
if err != nil {
return 0, err
}
total := machineMemory.Total
processMemory, err := p.MemoryInfo()
if err != nil {
return 0, err
}
used := processMemory.RSS
return (100 * float32(used) / float32(total)), nil
}

View File

@@ -4,7 +4,9 @@ package process
import (
"bytes"
"encoding/binary"
"fmt"
"os/exec"
"strconv"
"strings"
"syscall"
@@ -77,8 +79,11 @@ func (p *Process) Name() (string, error) {
return common.IntToString(k.Proc.P_comm[:]), nil
}
func (p *Process) Exe() (string, error) {
return "", common.NotImplementedError
return "", common.ErrNotImplementedError
}
// Cmdline returns the command line arguments of the process as a string with
// each argument separated by 0x20 ascii character.
func (p *Process) Cmdline() (string, error) {
r, err := callPs("command", p.Pid, false)
if err != nil {
@@ -86,11 +91,24 @@ func (p *Process) Cmdline() (string, error) {
}
return strings.Join(r[0], " "), err
}
// CmdlineSlice returns the command line arguments of the process as a slice with each
// element being an argument. Because of current deficiencies in the way that the command
// line arguments are found, single arguments that have spaces in the will actually be
// reported as two separate items. In order to do something better CGO would be needed
// to use the native darwin functions.
func (p *Process) CmdlineSlice() ([]string, error) {
r, err := callPs("command", p.Pid, false)
if err != nil {
return nil, err
}
return r[0], err
}
func (p *Process) CreateTime() (int64, error) {
return 0, common.NotImplementedError
return 0, common.ErrNotImplementedError
}
func (p *Process) Cwd() (string, error) {
return "", common.NotImplementedError
return "", common.ErrNotImplementedError
}
func (p *Process) Parent() (*Process, error) {
rr, err := common.CallLsof(invoke, p.Pid, "-FR")
@@ -124,11 +142,10 @@ func (p *Process) Uids() ([]int32, error) {
return nil, err
}
uids := make([]int32, 0, 3)
// See: http://unix.superglobalmegacorp.com/Net2/newsrc/sys/ucred.h.html
userEffectiveUID := int32(k.Eproc.Ucred.UID)
uids = append(uids, int32(k.Eproc.Pcred.P_ruid), int32(k.Eproc.Ucred.Uid), int32(k.Eproc.Pcred.P_svuid))
return uids, nil
return []int32{userEffectiveUID}, nil
}
func (p *Process) Gids() ([]int32, error) {
k, err := p.getKProc()
@@ -142,7 +159,7 @@ func (p *Process) Gids() ([]int32, error) {
return gids, nil
}
func (p *Process) Terminal() (string, error) {
return "", common.NotImplementedError
return "", common.ErrNotImplementedError
/*
k, err := p.getKProc()
if err != nil {
@@ -166,20 +183,20 @@ func (p *Process) Nice() (int32, error) {
return int32(k.Proc.P_nice), nil
}
func (p *Process) IOnice() (int32, error) {
return 0, common.NotImplementedError
return 0, common.ErrNotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
var rlimit []RlimitStat
return rlimit, common.NotImplementedError
return rlimit, common.ErrNotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
return 0, common.NotImplementedError
return 0, common.ErrNotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
r, err := callPs("utime,stime", p.Pid, true)
@@ -190,10 +207,10 @@ func (p *Process) NumThreads() (int32, error) {
}
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, common.NotImplementedError
return ret, common.ErrNotImplementedError
}
func convertCpuTimes(s string) (ret float64, err error) {
func convertCPUTimes(s string) (ret float64, err error) {
var t int
var _tmp string
if strings.Contains(s, ":") {
@@ -218,23 +235,23 @@ func convertCpuTimes(s string) (ret float64, err error) {
t += h
return float64(t) / ClockTicks, nil
}
func (p *Process) CPUTimes() (*cpu.CPUTimesStat, error) {
func (p *Process) Times() (*cpu.TimesStat, error) {
r, err := callPs("utime,stime", p.Pid, false)
if err != nil {
return nil, err
}
utime, err := convertCpuTimes(r[0][0])
utime, err := convertCPUTimes(r[0][0])
if err != nil {
return nil, err
}
stime, err := convertCpuTimes(r[0][1])
stime, err := convertCPUTimes(r[0][1])
if err != nil {
return nil, err
}
ret := &cpu.CPUTimesStat{
ret := &cpu.TimesStat{
CPU: "cpu",
User: utime,
System: stime,
@@ -242,7 +259,7 @@ func (p *Process) CPUTimes() (*cpu.CPUTimesStat, error) {
return ret, nil
}
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
r, err := callPs("rss,vsize,pagein", p.Pid, false)
@@ -271,10 +288,7 @@ func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
return ret, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryPercent() (float32, error) {
return 0, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) Children() ([]*Process, error) {
@@ -294,24 +308,23 @@ func (p *Process) Children() ([]*Process, error) {
}
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) Connections() ([]net.NetConnectionStat, error) {
return net.NetConnectionsPid("all", p.Pid)
func (p *Process) Connections() ([]net.ConnectionStat, error) {
return net.ConnectionsPid("all", p.Pid)
}
func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return true, common.NotImplementedError
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
var ret []MemoryMapsStat
return &ret, common.NotImplementedError
}
func copyParams(k *KinfoProc, p *Process) error {
return nil
return &ret, common.ErrNotImplementedError
}
func processes() ([]Process, error) {
@@ -346,8 +359,6 @@ func processes() ([]Process, error) {
if err != nil {
continue
}
copyParams(&k, p)
results = append(results, *p)
}
@@ -358,7 +369,7 @@ func parseKinfoProc(buf []byte) (KinfoProc, error) {
var k KinfoProc
br := bytes.NewReader(buf)
err := Read(br, LittleEndian, &k)
err := common.Read(br, binary.LittleEndian, &k)
if err != nil {
return k, err
}
@@ -366,6 +377,8 @@ func parseKinfoProc(buf []byte) (KinfoProc, error) {
return k, nil
}
// Returns a proc as defined here:
// http://unix.superglobalmegacorp.com/Net2/newsrc/sys/kinfo_proc.h.html
func (p *Process) getKProc() (*KinfoProc, error) {
mib := []int32{CTLKern, KernProc, KernProcPID, p.Pid}
procK := KinfoProc{}
@@ -401,15 +414,20 @@ func NewProcess(pid int32) (*Process, error) {
// 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) {
bin, err := exec.LookPath("ps")
if err != nil {
return [][]string{}, err
}
var cmd []string
if pid == 0 { // will get from all processes.
cmd = []string{"-x", "-o", arg}
cmd = []string{"-ax", "-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...)
out, err := invoke.Command(bin, cmd...)
if err != nil {
return [][]string{}, err
}

View File

@@ -101,7 +101,7 @@ type ucred struct {
type Uucred struct {
Ref int32
Uid uint32
UID uint32
Ngroups int16
Pad_cgo_0 [2]byte
Groups [16]uint32
@@ -197,7 +197,7 @@ type Au_session struct {
}
type Posix_cred struct {
Uid uint32
UID uint32
Ruid uint32
Svuid uint32
Ngroups int16

View File

@@ -5,7 +5,6 @@ package process
import (
"bytes"
"encoding/binary"
"unsafe"
"strings"
"syscall"
@@ -41,7 +40,7 @@ func (p *Process) Ppid() (int32, error) {
return 0, err
}
return k.KiPpid, nil
return k.Ppid, nil
}
func (p *Process) Name() (string, error) {
k, err := p.getKProc()
@@ -49,11 +48,12 @@ func (p *Process) Name() (string, error) {
return "", err
}
return string(k.KiComm[:]), nil
return common.IntToString(k.Comm[:]), nil
}
func (p *Process) Exe() (string, error) {
return "", common.NotImplementedError
return "", common.ErrNotImplementedError
}
func (p *Process) Cmdline() (string, error) {
mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
buf, _, err := common.CallSyscall(mib)
@@ -69,22 +69,60 @@ func (p *Process) Cmdline() (string, error) {
return strings.Join(ret, " "), nil
}
func (p *Process) CmdlineSlice() ([]string, error) {
mib := []int32{CTLKern, KernProc, KernProcArgs, p.Pid}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return nil, err
}
if len(buf) == 0 {
return nil, nil
}
if buf[len(buf)-1] == 0 {
buf = buf[:len(buf)-1]
}
parts := bytes.Split(buf, []byte{0})
var strParts []string
for _, p := range parts {
strParts = append(strParts, string(p))
}
return strParts, nil
}
func (p *Process) CreateTime() (int64, error) {
return 0, common.NotImplementedError
return 0, common.ErrNotImplementedError
}
func (p *Process) Cwd() (string, error) {
return "", common.NotImplementedError
return "", common.ErrNotImplementedError
}
func (p *Process) Parent() (*Process, error) {
return p, common.NotImplementedError
return p, common.ErrNotImplementedError
}
func (p *Process) Status() (string, error) {
k, err := p.getKProc()
if err != nil {
return "", err
}
var s string
switch k.Stat {
case SIDL:
s = "I"
case SRUN:
s = "R"
case SSLEEP:
s = "S"
case SSTOP:
s = "T"
case SZOMB:
s = "Z"
case SWAIT:
s = "W"
case SLOCK:
s = "L"
}
return string(k.KiStat[:]), nil
return s, nil
}
func (p *Process) Uids() ([]int32, error) {
k, err := p.getKProc()
@@ -94,7 +132,7 @@ func (p *Process) Uids() ([]int32, error) {
uids := make([]int32, 0, 3)
uids = append(uids, int32(k.KiRuid), int32(k.KiUID), int32(k.KiSvuid))
uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid))
return uids, nil
}
@@ -105,7 +143,7 @@ func (p *Process) Gids() ([]int32, error) {
}
gids := make([]int32, 0, 3)
gids = append(gids, int32(k.KiRgid), int32(k.KiNgroups[0]), int32(k.KiSvuid))
gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid))
return gids, nil
}
@@ -115,7 +153,7 @@ func (p *Process) Terminal() (string, error) {
return "", err
}
ttyNr := uint64(k.KiTdev)
ttyNr := uint64(k.Tdev)
termmap, err := getTerminalMap()
if err != nil {
@@ -125,14 +163,18 @@ func (p *Process) Terminal() (string, error) {
return termmap[ttyNr], nil
}
func (p *Process) Nice() (int32, error) {
return 0, common.NotImplementedError
k, err := p.getKProc()
if err != nil {
return 0, err
}
return int32(k.Nice), nil
}
func (p *Process) IOnice() (int32, error) {
return 0, common.NotImplementedError
return 0, common.ErrNotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
var rlimit []RlimitStat
return rlimit, common.NotImplementedError
return rlimit, common.ErrNotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
k, err := p.getKProc()
@@ -140,15 +182,15 @@ func (p *Process) IOCounters() (*IOCountersStat, error) {
return nil, err
}
return &IOCountersStat{
ReadCount: uint64(k.KiRusage.Inblock),
WriteCount: uint64(k.KiRusage.Oublock),
ReadCount: uint64(k.Rusage.Inblock),
WriteCount: uint64(k.Rusage.Oublock),
}, nil
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
return 0, common.NotImplementedError
return 0, common.ErrNotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
k, err := p.getKProc()
@@ -156,25 +198,25 @@ func (p *Process) NumThreads() (int32, error) {
return 0, err
}
return k.KiNumthreads, nil
return k.Numthreads, nil
}
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, common.NotImplementedError
return ret, common.ErrNotImplementedError
}
func (p *Process) CPUTimes() (*cpu.CPUTimesStat, error) {
func (p *Process) Times() (*cpu.TimesStat, error) {
k, err := p.getKProc()
if err != nil {
return nil, err
}
return &cpu.CPUTimesStat{
return &cpu.TimesStat{
CPU: "cpu",
User: float64(k.KiRusage.Utime.Sec) + float64(k.KiRusage.Utime.Usec)/1000000,
System: float64(k.KiRusage.Stime.Sec) + float64(k.KiRusage.Stime.Usec)/1000000,
User: float64(k.Rusage.Utime.Sec) + float64(k.Rusage.Utime.Usec)/1000000,
System: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000,
}, nil
}
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
k, err := p.getKProc()
@@ -185,18 +227,15 @@ func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
if err != nil {
return nil, err
}
pageSize := binary.LittleEndian.Uint16([]byte(v))
pageSize := common.LittleEndian.Uint16([]byte(v))
return &MemoryInfoStat{
RSS: uint64(k.KiRssize) * uint64(pageSize),
VMS: uint64(k.KiSize),
RSS: uint64(k.Rssize) * uint64(pageSize),
VMS: uint64(k.Size),
}, nil
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryPercent() (float32, error) {
return 0, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) Children() ([]*Process, error) {
@@ -216,24 +255,23 @@ func (p *Process) Children() ([]*Process, error) {
}
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) Connections() ([]net.NetConnectionStat, error) {
return nil, common.NotImplementedError
func (p *Process) Connections() ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return true, common.NotImplementedError
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
var ret []MemoryMapsStat
return &ret, common.NotImplementedError
}
func copyParams(k *KinfoProc, p *Process) error {
return nil
return &ret, common.ErrNotImplementedError
}
func processes() ([]Process, error) {
@@ -246,22 +284,19 @@ func processes() ([]Process, error) {
}
// get kinfo_proc size
k := KinfoProc{}
procinfoLen := int(unsafe.Sizeof(k))
count := int(length / uint64(procinfoLen))
count := int(length / uint64(sizeOfKinfoProc))
// parse buf to procs
for i := 0; i < count; i++ {
b := buf[i*procinfoLen : i*procinfoLen+procinfoLen]
b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc]
k, err := parseKinfoProc(b)
if err != nil {
continue
}
p, err := NewProcess(int32(k.KiPid))
p, err := NewProcess(int32(k.Pid))
if err != nil {
continue
}
copyParams(&k, p)
results = append(results, *p)
}
@@ -272,7 +307,7 @@ func processes() ([]Process, error) {
func parseKinfoProc(buf []byte) (KinfoProc, error) {
var k KinfoProc
br := bytes.NewReader(buf)
err := binary.Read(br, binary.LittleEndian, &k)
err := common.Read(br, binary.LittleEndian, &k)
return k, err
}
@@ -283,8 +318,7 @@ func (p *Process) getKProc() (*KinfoProc, error) {
if err != nil {
return nil, err
}
procK := KinfoProc{}
if length != uint64(unsafe.Sizeof(procK)) {
if length != sizeOfKinfoProc {
return nil, err
}
@@ -292,7 +326,6 @@ func (p *Process) getKProc() (*KinfoProc, error) {
if err != nil {
return nil, err
}
return &k, nil
}

View File

@@ -1,126 +1,192 @@
// +build freebsd
// +build 386
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go
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
KernProcArgs = 7 // get/set arguments/proctitle
CTLKern = 1
KernProc = 14
KernProcPID = 1
KernProcProc = 8
KernProcPathname = 12
KernProcArgs = 7
)
const (
sizeofPtr = 0x4
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x4
sizeofLongLong = 0x8
)
const (
sizeOfKinfoVmentry = 0x488
sizeOfKinfoProc = 0x300
)
const (
SIDL = 1
SRUN = 2
SSLEEP = 3
SSTOP = 4
SZOMB = 5
SWAIT = 6
SLOCK = 7
)
type (
_C_short int16
_C_int int32
_C_long int32
_C_long_long int64
)
type Timespec struct {
Sec int32
Nsec int32
Sec int32
Nsec int32
}
type Timeval struct {
Sec int32
Usec int32
Sec int32
Usec int32
}
type Rusage struct {
Utime Timeval
Stime Timeval
Maxrss int32
Ixrss int32
Idrss int32
Isrss int32
Minflt int32
Majflt int32
Nswap int32
Inblock int32
Oublock int32
Msgsnd int32
Msgrcv int32
Nsignals int32
Nvcsw int32
Nivcsw int32
Utime Timeval
Stime Timeval
Maxrss int32
Ixrss int32
Idrss int32
Isrss int32
Minflt int32
Majflt int32
Nswap int32
Inblock int32
Oublock int32
Msgsnd int32
Msgrcv int32
Nsignals int32
Nvcsw int32
Nivcsw int32
}
// 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 Rusage
KiRusageCh [72]byte
KiPcb int32
KiKstack int32
KiUdata int32
KiTdaddr int32
KiSpareptrs [24]byte
KiSpareint64s [48]byte
KiSflag int32
KiTdflags int32
type Rlimit struct {
Cur int64
Max int64
}
type KinfoProc struct {
Structsize int32
Layout int32
Args int32 /* pargs */
Paddr int32 /* proc */
Addr int32 /* user */
Tracep int32 /* vnode */
Textvp int32 /* vnode */
Fd int32 /* filedesc */
Vmspace int32 /* vmspace */
Wchan int32
Pid int32
Ppid int32
Pgid int32
Tpgid int32
Sid int32
Tsid int32
Jobc int16
Spare_short1 int16
Tdev uint32
Siglist [16]byte /* sigset */
Sigmask [16]byte /* sigset */
Sigignore [16]byte /* sigset */
Sigcatch [16]byte /* sigset */
Uid uint32
Ruid uint32
Svuid uint32
Rgid uint32
Svgid uint32
Ngroups int16
Spare_short2 int16
Groups [16]uint32
Size uint32
Rssize int32
Swrss int32
Tsize int32
Dsize int32
Ssize int32
Xstat uint16
Acflag uint16
Pctcpu uint32
Estcpu uint32
Slptime uint32
Swtime uint32
Cow uint32
Runtime uint64
Start Timeval
Childtime Timeval
Flag int32
Kiflag int32
Traceflag int32
Stat int8
Nice int8
Lock int8
Rqindex int8
Oncpu uint8
Lastcpu uint8
Tdname [17]int8
Wmesg [9]int8
Login [18]int8
Lockname [9]int8
Comm [20]int8
Emul [17]int8
Loginclass [18]int8
Sparestrings [50]int8
Spareints [7]int32
Flag2 int32
Fibnum int32
Cr_flags uint32
Jid int32
Numthreads int32
Tid int32
Pri Priority
Rusage Rusage
Rusage_ch Rusage
Pcb int32 /* pcb */
Kstack int32
Udata int32
Tdaddr int32 /* thread */
Spareptrs [6]int32
Sparelongs [12]int32
Sflag int32
Tdflags int32
}
type Priority struct {
Class uint8
Level uint8
Native uint8
User uint8
}
type KinfoVmentry struct {
Structsize int32
Type int32
Start uint64
End uint64
Offset uint64
Vn_fileid uint64
Vn_fsid uint32
Flags int32
Resident int32
Private_resident int32
Protection int32
Ref_count int32
Shadow_count int32
Vn_type int32
Vn_size uint64
Vn_rdev uint32
Vn_mode uint16
Status uint16
X_kve_ispare [12]int32
Path [1024]int8
}

View File

@@ -1,125 +1,192 @@
// +build freebsd
// +build amd64
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs types_freebsd.go
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
KernProcArgs = 7 // get/set arguments/proctitle
CTLKern = 1
KernProc = 14
KernProcPID = 1
KernProcProc = 8
KernProcPathname = 12
KernProcArgs = 7
)
const (
sizeofPtr = 0x8
sizeofShort = 0x2
sizeofInt = 0x4
sizeofLong = 0x8
sizeofLongLong = 0x8
)
const (
sizeOfKinfoVmentry = 0x488
sizeOfKinfoProc = 0x440
)
const (
SIDL = 1
SRUN = 2
SSLEEP = 3
SSTOP = 4
SZOMB = 5
SWAIT = 6
SLOCK = 7
)
type (
_C_short int16
_C_int int32
_C_long int64
_C_long_long int64
)
type Timespec struct {
Sec int64
Nsec int64
Sec int64
Nsec int64
}
type Timeval struct {
Sec int64
Usec int64
Sec int64
Usec int64
}
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
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
}
// 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 Rusage
KiRusageCh [144]byte
KiPcb int64
KiKstack int64
KiUdata int64
KiTdaddr int64
KiSpareptrs [48]byte
KiSpareint64s [96]byte
KiSflag int64
KiTdflags int64
type Rlimit struct {
Cur int64
Max int64
}
type KinfoProc struct {
Structsize int32
Layout int32
Args int64 /* pargs */
Paddr int64 /* proc */
Addr int64 /* user */
Tracep int64 /* vnode */
Textvp int64 /* vnode */
Fd int64 /* filedesc */
Vmspace int64 /* vmspace */
Wchan int64
Pid int32
Ppid int32
Pgid int32
Tpgid int32
Sid int32
Tsid int32
Jobc int16
Spare_short1 int16
Tdev uint32
Siglist [16]byte /* sigset */
Sigmask [16]byte /* sigset */
Sigignore [16]byte /* sigset */
Sigcatch [16]byte /* sigset */
Uid uint32
Ruid uint32
Svuid uint32
Rgid uint32
Svgid uint32
Ngroups int16
Spare_short2 int16
Groups [16]uint32
Size uint64
Rssize int64
Swrss int64
Tsize int64
Dsize int64
Ssize int64
Xstat uint16
Acflag uint16
Pctcpu uint32
Estcpu uint32
Slptime uint32
Swtime uint32
Cow uint32
Runtime uint64
Start Timeval
Childtime Timeval
Flag int64
Kiflag int64
Traceflag int32
Stat int8
Nice int8
Lock int8
Rqindex int8
Oncpu uint8
Lastcpu uint8
Tdname [17]int8
Wmesg [9]int8
Login [18]int8
Lockname [9]int8
Comm [20]int8
Emul [17]int8
Loginclass [18]int8
Sparestrings [50]int8
Spareints [7]int32
Flag2 int32
Fibnum int32
Cr_flags uint32
Jid int32
Numthreads int32
Tid int32
Pri Priority
Rusage Rusage
Rusage_ch Rusage
Pcb int64 /* pcb */
Kstack int64
Udata int64
Tdaddr int64 /* thread */
Spareptrs [6]int64
Sparelongs [12]int64
Sflag int64
Tdflags int64
}
type Priority struct {
Class uint8
Level uint8
Native uint8
User uint8
}
type KinfoVmentry struct {
Structsize int32
Type int32
Start uint64
End uint64
Offset uint64
Vn_fileid uint64
Vn_fsid uint32
Flags int32
Resident int32
Private_resident int32
Protection int32
Ref_count int32
Shadow_count int32
Vn_type int32
Vn_size uint64
Vn_rdev uint32
Vn_mode uint16
Status uint16
X_kve_ispare [12]int32
Path [1024]int8
}

View File

@@ -3,7 +3,9 @@
package process
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
@@ -18,6 +20,8 @@ import (
"github.com/shirou/gopsutil/net"
)
var ErrorNoChildren = errors.New("process does not have children")
const (
PrioProcess = 0 // linux/resource.h
)
@@ -43,30 +47,35 @@ type MemoryMapsStat struct {
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"`
SharedClean uint64 `json:"sharedClean"`
SharedDirty uint64 `json:"sharedDirty"`
PrivateClean uint64 `json:"privateClean"`
PrivateDirty uint64 `json:"privateDirty"`
Referenced uint64 `json:"referenced"`
Anonymous uint64 `json:"anonymous"`
Swap uint64 `json:"swap"`
}
// String returns JSON value of the process.
func (m MemoryMapsStat) String() string {
s, _ := json.Marshal(m)
return string(s)
}
// Create new Process instance
// This only stores Pid
// NewProcess creates a new Process instance, it only stores the pid and
// checks that the process exists. Other method on Process can be used
// to get more information about the process. An error will be returned
// if the process does not exist.
func NewProcess(pid int32) (*Process, error) {
p := &Process{
Pid: int32(pid),
}
err := p.fillFromStatus()
file, err := os.Open(common.HostProc(strconv.Itoa(int(p.Pid))))
defer file.Close()
return p, err
}
// Ppid returns Parent Process ID of the process.
func (p *Process) Ppid() (int32, error) {
_, ppid, _, _, _, err := p.fillFromStat()
if err != nil {
@@ -74,15 +83,35 @@ func (p *Process) Ppid() (int32, error) {
}
return ppid, nil
}
// Name returns name of the process.
func (p *Process) Name() (string, error) {
if p.name == "" {
if err := p.fillFromStatus(); err != nil {
return "", err
}
}
return p.name, nil
}
// Exe returns executable path of the process.
func (p *Process) Exe() (string, error) {
return p.fillFromExe()
}
// Cmdline returns the command line arguments of the process as a string with
// each argument separated by 0x20 ascii character.
func (p *Process) Cmdline() (string, error) {
return p.fillFromCmdline()
}
// CmdlineSlice returns the command line arguments of the process as a slice with each
// element being an argument.
func (p *Process) CmdlineSlice() ([]string, error) {
return p.fillSliceFromCmdline()
}
// CreateTime returns created time of the process in seconds since the epoch, in UTC.
func (p *Process) CreateTime() (int64, error) {
_, _, _, createTime, _, err := p.fillFromStat()
if err != nil {
@@ -91,23 +120,28 @@ func (p *Process) CreateTime() (int64, error) {
return createTime, nil
}
// Cwd returns current working directory of the process.
func (p *Process) Cwd() (string, error) {
return p.fillFromCwd()
}
// Parent returns parent Process of the process.
func (p *Process) Parent() (*Process, error) {
r, err := callLsof("R", p.Pid)
err := p.fillFromStatus()
if err != nil {
return nil, err
}
if len(r) != 1 { // TODO: pid 1
if p.parent == 0 {
return nil, fmt.Errorf("wrong number of parents")
}
v, err := strconv.Atoi(r[0])
if err != nil {
return nil, err
}
return NewProcess(int32(v))
return NewProcess(p.parent)
}
// Status returns the process status.
// Return value could be one of these.
// R: Running S: Sleep T: Stop I: Idle
// Z: Zombie W: Wait L: Lock
// The charactor is same within all supported platforms.
func (p *Process) Status() (string, error) {
err := p.fillFromStatus()
if err != nil {
@@ -115,6 +149,8 @@ func (p *Process) Status() (string, error) {
}
return p.status, nil
}
// Uids returns user ids of the process as a slice of the int
func (p *Process) Uids() ([]int32, error) {
err := p.fillFromStatus()
if err != nil {
@@ -122,6 +158,8 @@ func (p *Process) Uids() ([]int32, error) {
}
return p.uids, nil
}
// Gids returns group ids of the process as a slice of the int
func (p *Process) Gids() ([]int32, error) {
err := p.fillFromStatus()
if err != nil {
@@ -129,6 +167,8 @@ func (p *Process) Gids() ([]int32, error) {
}
return p.gids, nil
}
// Terminal returns a terminal which is associated with the process.
func (p *Process) Terminal() (string, error) {
terminal, _, _, _, _, err := p.fillFromStat()
if err != nil {
@@ -136,6 +176,9 @@ func (p *Process) Terminal() (string, error) {
}
return terminal, nil
}
// Nice returns a nice value (priority).
// Notice: gopsutil can not set nice value.
func (p *Process) Nice() (int32, error) {
_, _, _, _, nice, err := p.fillFromStat()
if err != nil {
@@ -143,15 +186,23 @@ func (p *Process) Nice() (int32, error) {
}
return nice, nil
}
// IOnice returns process I/O nice value (priority).
func (p *Process) IOnice() (int32, error) {
return 0, common.NotImplementedError
return 0, common.ErrNotImplementedError
}
// Rlimit returns Resource Limits.
func (p *Process) Rlimit() ([]RlimitStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
// IOCounters returns IO Counters.
func (p *Process) IOCounters() (*IOCountersStat, error) {
return p.fillFromIO()
}
// NumCtxSwitches returns the number of the context switches of the process.
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
err := p.fillFromStatus()
if err != nil {
@@ -159,10 +210,14 @@ func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
}
return p.numCtxSwitches, nil
}
// NumFDs returns the number of File Descriptors used by the process.
func (p *Process) NumFDs() (int32, error) {
numFds, _, err := p.fillFromfd()
return numFds, err
}
// NumThreads returns the number of threads used by the process.
func (p *Process) NumThreads() (int32, error) {
err := p.fillFromStatus()
if err != nil {
@@ -170,27 +225,41 @@ func (p *Process) NumThreads() (int32, error) {
}
return p.numThreads, nil
}
// Threads returns a map of threads
//
// Notice: Not implemented yet. always returns empty map.
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, nil
}
func (p *Process) CPUTimes() (*cpu.CPUTimesStat, error) {
// Times returns CPU times of the process.
func (p *Process) Times() (*cpu.TimesStat, error) {
_, _, cpuTimes, _, _, err := p.fillFromStat()
if err != nil {
return nil, err
}
return cpuTimes, nil
}
// CPUAffinity returns CPU affinity of the process.
//
// Notice: Not implemented yet.
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
// MemoryInfo returns platform in-dependend memory information, such as RSS, VMS and Swap
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
_, _, err := p.fillFromStatm()
meminfo, _, err := p.fillFromStatm()
if err != nil {
return nil, err
}
return p.memInfo, nil
return meminfo, nil
}
// MemoryInfoEx returns platform dependend memory information.
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
_, memInfoEx, err := p.fillFromStatm()
if err != nil {
@@ -198,13 +267,14 @@ func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
}
return memInfoEx, nil
}
func (p *Process) MemoryPercent() (float32, error) {
return 0, common.NotImplementedError
}
// Children returns a slice of Process of the process.
func (p *Process) Children() ([]*Process, error) {
pids, err := common.CallPgrep(invoke, p.Pid)
if err != nil {
if pids == nil || len(pids) == 0 {
return nil, ErrorNoChildren
}
return nil, err
}
ret := make([]*Process, 0, len(pids))
@@ -218,12 +288,14 @@ func (p *Process) Children() ([]*Process, error) {
return ret, nil
}
// OpenFiles returns a slice of OpenFilesStat opend by the process.
// OpenFilesStat includes a file path and file descriptor.
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
_, ofs, err := p.fillFromfd()
if err != nil {
return nil, err
}
ret := make([]OpenFilesStat, 0, len(ofs))
ret := make([]OpenFilesStat, len(ofs))
for i, o := range ofs {
ret[i] = *o
}
@@ -231,12 +303,22 @@ func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return ret, nil
}
func (p *Process) Connections() ([]net.NetConnectionStat, error) {
return net.NetConnectionsPid("all", p.Pid)
// Connections returns a slice of net.ConnectionStat used by the process.
// This returns all kind of the connection. This measn TCP, UDP or UNIX.
func (p *Process) Connections() ([]net.ConnectionStat, error) {
return net.ConnectionsPid("all", p.Pid)
}
// NetIOCounters returns NetIOCounters of the process.
func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
filename := common.HostProc(strconv.Itoa(int(p.Pid)), "net/dev")
return net.IOCountersByFile(pernic, filename)
}
// IsRunning returns whether the process is running or not.
// Not implemented yet.
func (p *Process) IsRunning() (bool, error) {
return true, common.NotImplementedError
return true, common.ErrNotImplementedError
}
// MemoryMaps get memory maps from /proc/(pid)/smaps
@@ -333,7 +415,7 @@ func (p *Process) fillFromfd() (int32, []*OpenFilesStat, error) {
fnames, err := d.Readdirnames(-1)
numFDs := int32(len(fnames))
openfiles := make([]*OpenFilesStat, numFDs)
var openfiles []*OpenFilesStat
for _, fd := range fnames {
fpath := filepath.Join(statPath, fd)
filepath, err := os.Readlink(fpath)
@@ -394,6 +476,28 @@ func (p *Process) fillFromCmdline() (string, error) {
return strings.Join(ret, " "), nil
}
func (p *Process) fillSliceFromCmdline() ([]string, error) {
pid := p.Pid
cmdPath := common.HostProc(strconv.Itoa(int(pid)), "cmdline")
cmdline, err := ioutil.ReadFile(cmdPath)
if err != nil {
return nil, err
}
if len(cmdline) == 0 {
return nil, nil
}
if cmdline[len(cmdline)-1] == 0 {
cmdline = cmdline[:len(cmdline)-1]
}
parts := bytes.Split(cmdline, []byte{0})
var strParts []string
for _, p := range parts {
strParts = append(strParts, string(p))
}
return strParts, nil
}
// Get IO status from /proc/(pid)/io
func (p *Process) fillFromIO() (*IOCountersStat, error) {
pid := p.Pid
@@ -423,9 +527,9 @@ func (p *Process) fillFromIO() (*IOCountersStat, error) {
ret.ReadCount = t
case "syscw":
ret.WriteCount = t
case "read_bytes":
case "readBytes":
ret.ReadBytes = t
case "write_bytes":
case "writeBytes":
ret.WriteBytes = t
}
}
@@ -506,10 +610,13 @@ func (p *Process) fillFromStatus() error {
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]
p.status = value[0:1]
case "PPid", "Ppid":
pval, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return err
}
p.parent = int32(pval)
case "Uid":
p.uids = make([]int32, 0, 4)
for _, i := range strings.Split(value, "\t") {
@@ -573,7 +680,7 @@ func (p *Process) fillFromStatus() error {
return nil
}
func (p *Process) fillFromStat() (string, int32, *cpu.CPUTimesStat, int64, int32, error) {
func (p *Process) fillFromStat() (string, int32, *cpu.TimesStat, int64, int32, error) {
pid := p.Pid
statPath := common.HostProc(strconv.Itoa(int(pid)), "stat")
contents, err := ioutil.ReadFile(statPath)
@@ -611,7 +718,7 @@ func (p *Process) fillFromStat() (string, int32, *cpu.CPUTimesStat, int64, int32
return "", 0, nil, 0, 0, err
}
cpuTimes := &cpu.CPUTimesStat{
cpuTimes := &cpu.TimesStat{
CPU: "cpu",
User: float64(utime / ClockTicks),
System: float64(stime / ClockTicks),
@@ -633,6 +740,7 @@ func (p *Process) fillFromStat() (string, int32, *cpu.CPUTimesStat, int64, int32
return terminal, int32(ppid), cpuTimes, createTime, nice, nil
}
// Pids returns a slice of process ID list which are running now.
func Pids() ([]int32, error) {
var ret []int32
@@ -657,26 +765,3 @@ func Pids() ([]int32, error) {
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

@@ -51,6 +51,8 @@ func getTerminalMap() (map[uint64]string, error) {
return ret, nil
}
// SendSignal sends a syscall.Signal to the process.
// Currently, SIGSTOP, SIGCONT, SIGTERM and SIGKILL are supported.
func (p *Process) SendSignal(sig syscall.Signal) error {
sigAsStr := "INT"
switch sig {
@@ -64,9 +66,13 @@ func (p *Process) SendSignal(sig syscall.Signal) error {
sigAsStr = "KILL"
}
cmd := exec.Command("kill", "-s", sigAsStr, strconv.Itoa(int(p.Pid)))
kill, err := exec.LookPath("kill")
if err != nil {
return err
}
cmd := exec.Command(kill, "-s", sigAsStr, strconv.Itoa(int(p.Pid)))
cmd.Stderr = os.Stderr
err := cmd.Run()
err = cmd.Run()
if err != nil {
return err
}
@@ -74,18 +80,27 @@ func (p *Process) SendSignal(sig syscall.Signal) error {
return nil
}
// Suspend sends SIGSTOP to the process.
func (p *Process) Suspend() error {
return p.SendSignal(syscall.SIGSTOP)
}
// Resume sends SIGCONT to the process.
func (p *Process) Resume() error {
return p.SendSignal(syscall.SIGCONT)
}
// Terminate sends SIGTERM to the process.
func (p *Process) Terminate() error {
return p.SendSignal(syscall.SIGTERM)
}
// Kill sends SIGKILL to the process.
func (p *Process) Kill() error {
return p.SendSignal(syscall.SIGKILL)
}
// Username returns a username of the process.
func (p *Process) Username() (string, error) {
uids, err := p.Uids()
if err != nil {

View File

@@ -5,6 +5,7 @@ package process
import (
"errors"
"fmt"
"strings"
"syscall"
"time"
"unsafe"
@@ -12,8 +13,8 @@ import (
"github.com/StackExchange/wmi"
"github.com/shirou/w32"
"github.com/shirou/gopsutil/internal/common"
cpu "github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/internal/common"
net "github.com/shirou/gopsutil/net"
)
@@ -50,7 +51,7 @@ type Win32_Process struct {
CommandLine *string
Priority uint32
CreationDate *time.Time
ProcessId uint32
ProcessID uint32
ThreadCount uint32
/*
@@ -70,7 +71,7 @@ type Win32_Process struct {
OtherTransferCount uint64
PageFaults uint32
PageFileUsage uint32
ParentProcessId uint32
ParentProcessID uint32
PeakPageFileUsage uint32
PeakVirtualSize uint64
PeakWorkingSetSize uint32
@@ -145,6 +146,17 @@ func (p *Process) Cmdline() (string, error) {
return *dst[0].CommandLine, nil
}
// CmdlineSlice returns the command line arguments of the process as a slice with each
// element being an argument. This merely returns the CommandLine informations passed
// to the process split on the 0x20 ASCII character.
func (p *Process) CmdlineSlice() ([]string, error) {
cmdline, err := p.Cmdline()
if err != nil {
return nil, err
}
return strings.Split(cmdline, " "), nil
}
func (p *Process) CreateTime() (int64, error) {
dst, err := GetWin32Proc(p.Pid)
if err != nil {
@@ -155,28 +167,28 @@ func (p *Process) CreateTime() (int64, error) {
}
func (p *Process) Cwd() (string, error) {
return "", common.NotImplementedError
return "", common.ErrNotImplementedError
}
func (p *Process) Parent() (*Process, error) {
return p, common.NotImplementedError
return p, common.ErrNotImplementedError
}
func (p *Process) Status() (string, error) {
return "", common.NotImplementedError
return "", common.ErrNotImplementedError
}
func (p *Process) Username() (string, error) {
return "", common.NotImplementedError
return "", common.ErrNotImplementedError
}
func (p *Process) Uids() ([]int32, error) {
var uids []int32
return uids, common.NotImplementedError
return uids, common.ErrNotImplementedError
}
func (p *Process) Gids() ([]int32, error) {
var gids []int32
return gids, common.NotImplementedError
return gids, common.ErrNotImplementedError
}
func (p *Process) Terminal() (string, error) {
return "", common.NotImplementedError
return "", common.ErrNotImplementedError
}
// Nice returnes priority in Windows
@@ -188,21 +200,21 @@ func (p *Process) Nice() (int32, error) {
return int32(dst[0].Priority), nil
}
func (p *Process) IOnice() (int32, error) {
return 0, common.NotImplementedError
return 0, common.ErrNotImplementedError
}
func (p *Process) Rlimit() ([]RlimitStat, error) {
var rlimit []RlimitStat
return rlimit, common.NotImplementedError
return rlimit, common.ErrNotImplementedError
}
func (p *Process) IOCounters() (*IOCountersStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) NumFDs() (int32, error) {
return 0, common.NotImplementedError
return 0, common.ErrNotImplementedError
}
func (p *Process) NumThreads() (int32, error) {
dst, err := GetWin32Proc(p.Pid)
@@ -213,43 +225,44 @@ func (p *Process) NumThreads() (int32, error) {
}
func (p *Process) Threads() (map[string]string, error) {
ret := make(map[string]string, 0)
return ret, common.NotImplementedError
return ret, common.ErrNotImplementedError
}
func (p *Process) CPUTimes() (*cpu.CPUTimesStat, error) {
return nil, common.NotImplementedError
func (p *Process) Times() (*cpu.TimesStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) CPUAffinity() ([]int32, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) MemoryInfo() (*MemoryInfoStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) {
return nil, common.NotImplementedError
}
func (p *Process) MemoryPercent() (float32, error) {
return 0, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) Children() ([]*Process, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) OpenFiles() ([]OpenFilesStat, error) {
return nil, common.NotImplementedError
return nil, common.ErrNotImplementedError
}
func (p *Process) Connections() ([]net.NetConnectionStat, error) {
return nil, common.NotImplementedError
func (p *Process) Connections() ([]net.ConnectionStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) {
return nil, common.ErrNotImplementedError
}
func (p *Process) IsRunning() (bool, error) {
return true, common.NotImplementedError
return true, common.ErrNotImplementedError
}
func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) {
ret := make([]MemoryMapsStat, 0)
return &ret, common.NotImplementedError
var ret []MemoryMapsStat
return &ret, common.ErrNotImplementedError
}
func NewProcess(pid int32) (*Process, error) {
@@ -259,20 +272,20 @@ func NewProcess(pid int32) (*Process, error) {
}
func (p *Process) SendSignal(sig syscall.Signal) error {
return common.NotImplementedError
return common.ErrNotImplementedError
}
func (p *Process) Suspend() error {
return common.NotImplementedError
return common.ErrNotImplementedError
}
func (p *Process) Resume() error {
return common.NotImplementedError
return common.ErrNotImplementedError
}
func (p *Process) Terminate() error {
return common.NotImplementedError
return common.ErrNotImplementedError
}
func (p *Process) Kill() error {
return common.NotImplementedError
return common.ErrNotImplementedError
}
func (p *Process) getFromSnapProcess(pid int32) (int32, int32, string, error) {
@@ -315,7 +328,7 @@ func processes() ([]*Process, error) {
}
results := make([]*Process, 0, len(dst))
for _, proc := range dst {
p, err := NewProcess(int32(proc.ProcessId))
p, err := NewProcess(int32(proc.ProcessID))
if err != nil {
continue
}

View File

@@ -0,0 +1,95 @@
// +build ignore
// We still need editing by hands.
// go tool cgo -godefs types_freebsd.go | sed 's/\*int64/int64/' | sed 's/\*byte/int64/' > process_freebsd_amd64.go
/*
Input to cgo -godefs.
*/
// +godefs map struct_pargs int64 /* pargs */
// +godefs map struct_proc int64 /* proc */
// +godefs map struct_user int64 /* user */
// +godefs map struct_vnode int64 /* vnode */
// +godefs map struct_vnode int64 /* vnode */
// +godefs map struct_filedesc int64 /* filedesc */
// +godefs map struct_vmspace int64 /* vmspace */
// +godefs map struct_pcb int64 /* pcb */
// +godefs map struct_thread int64 /* thread */
// +godefs map struct___sigset [16]byte /* sigset */
package process
/*
#include <sys/types.h>
#include <sys/user.h>
enum {
sizeofPtr = sizeof(void*),
};
*/
import "C"
// Machine characteristics; for internal use.
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
KernProcArgs = 7 // get/set arguments/proctitle
)
const (
sizeofPtr = C.sizeofPtr
sizeofShort = C.sizeof_short
sizeofInt = C.sizeof_int
sizeofLong = C.sizeof_long
sizeofLongLong = C.sizeof_longlong
)
const (
sizeOfKinfoVmentry = C.sizeof_struct_kinfo_vmentry
sizeOfKinfoProc = C.sizeof_struct_kinfo_proc
)
// from sys/proc.h
const (
SIDL = 1 /* Process being created by fork. */
SRUN = 2 /* Currently runnable. */
SSLEEP = 3 /* Sleeping on an address. */
SSTOP = 4 /* Process debugging or suspension. */
SZOMB = 5 /* Awaiting collection by parent. */
SWAIT = 6 /* Waiting for interrupt. */
SLOCK = 7 /* Blocked on a lock. */
)
// 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 KinfoProc C.struct_kinfo_proc
type Priority C.struct_priority
type KinfoVmentry C.struct_kinfo_vmentry

24
vendor/vendor.json vendored
View File

@@ -606,34 +606,46 @@
"revision": "983d3a5fab1bf04d1b412465d2d9f8430e2e917e"
},
{
"checksumSHA1": "dtcffK/n1nDKPtvHg2GnU1C194s=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/cpu",
"revision": "f58654fa1c30aab9b8c503ecea4922e80abcd2bf"
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
},
{
"checksumSHA1": "lpPewrgMOYaTKZ0wRZpmZJxnEBw=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/host",
"revision": "f58654fa1c30aab9b8c503ecea4922e80abcd2bf"
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
},
{
"checksumSHA1": "xrMuUxCr8UckY5oI2lwCerYwIhk=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/internal/common",
"revision": "f58654fa1c30aab9b8c503ecea4922e80abcd2bf"
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
},
{
"checksumSHA1": "bHTDi2QAN4SmdZpHOtyQ6fQeCnQ=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/mem",
"revision": "f58654fa1c30aab9b8c503ecea4922e80abcd2bf"
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
},
{
"checksumSHA1": "LHJDMUXWamoP/yje0R42k96OPG8=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/net",
"revision": "f58654fa1c30aab9b8c503ecea4922e80abcd2bf"
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
},
{
"checksumSHA1": "o544bXejDPLi6qpjHav8a91W4Ks=",
"comment": "1.0.0-230-gf58654f",
"path": "github.com/shirou/gopsutil/process",
"revision": "f58654fa1c30aab9b8c503ecea4922e80abcd2bf"
"revision": "7b991b8135166c7fc81b65665a2f35c7a1966cfc",
"revisionTime": "2016-05-04T15:08:50Z"
},
{
"path": "github.com/shirou/w32",