From cba0992ab38a940baf5ff68dde35c39009e8b24d Mon Sep 17 00:00:00 2001 From: Jean Kahrs Date: Thu, 6 Oct 2016 14:50:03 +0200 Subject: [PATCH 1/5] add Uids field to net_linux --- net/net.go | 15 ++++++++------- net/net_linux.go | 8 ++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/net/net.go b/net/net.go index 4d120dc..48660ec 100644 --- a/net/net.go +++ b/net/net.go @@ -39,13 +39,14 @@ type Addr struct { } type ConnectionStat struct { - Fd uint32 `json:"fd"` - Family uint32 `json:"family"` - Type uint32 `json:"type"` - Laddr Addr `json:"localaddr"` - Raddr Addr `json:"remoteaddr"` - Status string `json:"status"` - Pid int32 `json:"pid"` + Fd uint32 `json:"fd"` + Family uint32 `json:"family"` + Type uint32 `json:"type"` + Laddr Addr `json:"localaddr"` + Raddr Addr `json:"remoteaddr"` + Status string `json:"status"` + Uids []int32 `json:"uids"` + Pid int32 `json:"pid"` } // System wide stats about different network protocols diff --git a/net/net_linux.go b/net/net_linux.go index 0803d8e..c9c5d40 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -14,6 +14,7 @@ import ( "syscall" "github.com/shirou/gopsutil/internal/common" + "github.com/shirou/gopsutil/process" ) // NetIOCounters returnes network I/O statistics for every network @@ -281,6 +282,7 @@ type connTmp struct { laddr Addr raddr Addr status string + uids []int32 pid int32 boundPid int32 path string @@ -338,6 +340,7 @@ func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { Type: c.sockType, Laddr: c.laddr, Raddr: c.raddr, + Uids: c.uids, Status: c.status, Pid: c.pid, } @@ -346,6 +349,11 @@ func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { } else { conn.Pid = c.pid } + + // fetch process owner Real, effective, saved set, and filesystem UIDs + proc := process.Process{Pid: conn.Pid} + conn.Uids, _ = proc.Uids() + // check duplicate using JSON format json := conn.String() _, exists := dupCheckMap[json] From ab24c97439d04a6f7faf29eb08da10c8d7e36415 Mon Sep 17 00:00:00 2001 From: Jean Kahrs Date: Thu, 6 Oct 2016 15:32:25 +0200 Subject: [PATCH 2/5] break import cycle --- net/net_linux.go | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 2 deletions(-) diff --git a/net/net_linux.go b/net/net_linux.go index c9c5d40..217bba1 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -12,9 +12,9 @@ import ( "strconv" "strings" "syscall" + "time" "github.com/shirou/gopsutil/internal/common" - "github.com/shirou/gopsutil/process" ) // NetIOCounters returnes network I/O statistics for every network @@ -351,7 +351,7 @@ func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { } // fetch process owner Real, effective, saved set, and filesystem UIDs - proc := process.Process{Pid: conn.Pid} + proc := Process{Pid: conn.Pid} conn.Uids, _ = proc.Uids() // check duplicate using JSON format @@ -437,6 +437,151 @@ func Pids() ([]int32, error) { return ret, nil } +// Note: the following are copys of cpu_linux / process_linux structs and methods +// we need these to fetch the owner of a process ID +// FIXME: Import process occures import cycle. +// see remarks on pids() +type TimesStat struct { + CPU string `json:"cpu"` + User float64 `json:"user"` + System float64 `json:"system"` + Idle float64 `json:"idle"` + Nice float64 `json:"nice"` + Iowait float64 `json:"iowait"` + Irq float64 `json:"irq"` + Softirq float64 `json:"softirq"` + Steal float64 `json:"steal"` + Guest float64 `json:"guest"` + GuestNice float64 `json:"guestNice"` + Stolen float64 `json:"stolen"` +} + +type Process struct { + Pid int32 `json:"pid"` + name string + status string + parent int32 + numCtxSwitches *NumCtxSwitchesStat + uids []int32 + gids []int32 + numThreads int32 + memInfo *MemoryInfoStat + + lastCPUTimes *TimesStat + lastCPUTime time.Time +} + +type MemoryInfoStat struct { + RSS uint64 `json:"rss"` // bytes + VMS uint64 `json:"vms"` // bytes + Swap uint64 `json:"swap"` // bytes +} + +type NumCtxSwitchesStat struct { + Voluntary int64 `json:"voluntary"` + Involuntary int64 `json:"involuntary"` +} + +// 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 { + return []int32{}, err + } + return p.uids, nil +} + +// Get various status from /proc/(pid)/status +func (p *Process) fillFromStatus() error { + pid := p.Pid + statPath := common.HostProc(strconv.Itoa(int(pid)), "status") + contents, err := ioutil.ReadFile(statPath) + if err != nil { + return err + } + lines := strings.Split(string(contents), "\n") + p.numCtxSwitches = &NumCtxSwitchesStat{} + p.memInfo = &MemoryInfoStat{} + for _, line := range lines { + tabParts := strings.SplitN(line, "\t", 2) + if len(tabParts) < 2 { + continue + } + value := tabParts[1] + switch strings.TrimRight(tabParts[0], ":") { + case "Name": + p.name = strings.Trim(value, " \t") + case "State": + 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") { + v, err := strconv.ParseInt(i, 10, 32) + if err != nil { + return err + } + p.uids = append(p.uids, int32(v)) + } + case "Gid": + p.gids = make([]int32, 0, 4) + for _, i := range strings.Split(value, "\t") { + v, err := strconv.ParseInt(i, 10, 32) + if err != nil { + return err + } + p.gids = append(p.gids, int32(v)) + } + case "Threads": + v, err := strconv.ParseInt(value, 10, 32) + if err != nil { + return err + } + p.numThreads = int32(v) + case "voluntary_ctxt_switches": + v, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + p.numCtxSwitches.Voluntary = v + case "nonvoluntary_ctxt_switches": + v, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + p.numCtxSwitches.Involuntary = v + case "VmRSS": + value := strings.Trim(value, " kB") // remove last "kB" + v, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return err + } + p.memInfo.RSS = v * 1024 + case "VmSize": + value := strings.Trim(value, " kB") // remove last "kB" + v, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return err + } + p.memInfo.VMS = v * 1024 + case "VmSwap": + value := strings.Trim(value, " kB") // remove last "kB" + v, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return err + } + p.memInfo.Swap = v * 1024 + } + + } + return nil +} + func getProcInodesAll(root string) (map[string][]inodeMap, error) { pids, err := Pids() if err != nil { From 98a0a30dca8125bdc1ea7bf64884a14fb5a7917e Mon Sep 17 00:00:00 2001 From: Jean Kahrs Date: Thu, 6 Oct 2016 15:38:56 +0200 Subject: [PATCH 3/5] update test --- net/net_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/net_test.go b/net/net_test.go index 9ec87ad..fb386c2 100644 --- a/net/net_test.go +++ b/net/net_test.go @@ -50,8 +50,9 @@ func TestNetConnectionStatString(t *testing.T) { Fd: 10, Family: 10, Type: 10, + Uids: []int32{10, 10} } - e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","pid":0}` + e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","uids":[10,10],"pid":0}` if e != fmt.Sprintf("%v", v) { t.Errorf("NetConnectionStat string is invalid: %v", v) } From d6f5a9e9205c73c7b1b380b17f819fbcd9d52cd9 Mon Sep 17 00:00:00 2001 From: Jean Kahrs Date: Thu, 6 Oct 2016 15:46:14 +0200 Subject: [PATCH 4/5] fix net_test.go --- net/net_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/net_test.go b/net/net_test.go index fb386c2..491a738 100644 --- a/net/net_test.go +++ b/net/net_test.go @@ -50,7 +50,7 @@ func TestNetConnectionStatString(t *testing.T) { Fd: 10, Family: 10, Type: 10, - Uids: []int32{10, 10} + Uids: []int32{10, 10}, } e := `{"fd":10,"family":10,"type":10,"localaddr":{"ip":"","port":0},"remoteaddr":{"ip":"","port":0},"status":"","uids":[10,10],"pid":0}` if e != fmt.Sprintf("%v", v) { From e004ef15e1a012a39ccba0bc5e379051a26ee3d9 Mon Sep 17 00:00:00 2001 From: Jean Kahrs Date: Tue, 11 Oct 2016 10:34:47 +0200 Subject: [PATCH 5/5] remove unused code --- net/net_linux.go | 116 +++++-------------------------------------------------- 1 file changed, 9 insertions(+), 107 deletions(-) diff --git a/net/net_linux.go b/net/net_linux.go index 217bba1..cb83e69 100644 --- a/net/net_linux.go +++ b/net/net_linux.go @@ -12,7 +12,6 @@ import ( "strconv" "strings" "syscall" - "time" "github.com/shirou/gopsutil/internal/common" ) @@ -351,8 +350,8 @@ func ConnectionsPid(kind string, pid int32) ([]ConnectionStat, error) { } // fetch process owner Real, effective, saved set, and filesystem UIDs - proc := Process{Pid: conn.Pid} - conn.Uids, _ = proc.Uids() + proc := process{Pid: conn.Pid} + conn.Uids, _ = proc.getUids() // check duplicate using JSON format json := conn.String() @@ -437,53 +436,17 @@ func Pids() ([]int32, error) { return ret, nil } -// Note: the following are copys of cpu_linux / process_linux structs and methods +// Note: the following is based off process_linux structs and methods // we need these to fetch the owner of a process ID // FIXME: Import process occures import cycle. // see remarks on pids() -type TimesStat struct { - CPU string `json:"cpu"` - User float64 `json:"user"` - System float64 `json:"system"` - Idle float64 `json:"idle"` - Nice float64 `json:"nice"` - Iowait float64 `json:"iowait"` - Irq float64 `json:"irq"` - Softirq float64 `json:"softirq"` - Steal float64 `json:"steal"` - Guest float64 `json:"guest"` - GuestNice float64 `json:"guestNice"` - Stolen float64 `json:"stolen"` -} - -type Process struct { - Pid int32 `json:"pid"` - name string - status string - parent int32 - numCtxSwitches *NumCtxSwitchesStat - uids []int32 - gids []int32 - numThreads int32 - memInfo *MemoryInfoStat - - lastCPUTimes *TimesStat - lastCPUTime time.Time -} - -type MemoryInfoStat struct { - RSS uint64 `json:"rss"` // bytes - VMS uint64 `json:"vms"` // bytes - Swap uint64 `json:"swap"` // bytes -} - -type NumCtxSwitchesStat struct { - Voluntary int64 `json:"voluntary"` - Involuntary int64 `json:"involuntary"` +type process struct { + Pid int32 `json:"pid"` + uids []int32 } // Uids returns user ids of the process as a slice of the int -func (p *Process) Uids() ([]int32, error) { +func (p *process) getUids() ([]int32, error) { err := p.fillFromStatus() if err != nil { return []int32{}, err @@ -491,8 +454,8 @@ func (p *Process) Uids() ([]int32, error) { return p.uids, nil } -// Get various status from /proc/(pid)/status -func (p *Process) fillFromStatus() error { +// Get status from /proc/(pid)/status +func (p *process) fillFromStatus() error { pid := p.Pid statPath := common.HostProc(strconv.Itoa(int(pid)), "status") contents, err := ioutil.ReadFile(statPath) @@ -500,8 +463,6 @@ func (p *Process) fillFromStatus() error { return err } lines := strings.Split(string(contents), "\n") - p.numCtxSwitches = &NumCtxSwitchesStat{} - p.memInfo = &MemoryInfoStat{} for _, line := range lines { tabParts := strings.SplitN(line, "\t", 2) if len(tabParts) < 2 { @@ -509,16 +470,6 @@ func (p *Process) fillFromStatus() error { } value := tabParts[1] switch strings.TrimRight(tabParts[0], ":") { - case "Name": - p.name = strings.Trim(value, " \t") - case "State": - 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") { @@ -528,56 +479,7 @@ func (p *Process) fillFromStatus() error { } p.uids = append(p.uids, int32(v)) } - case "Gid": - p.gids = make([]int32, 0, 4) - for _, i := range strings.Split(value, "\t") { - v, err := strconv.ParseInt(i, 10, 32) - if err != nil { - return err - } - p.gids = append(p.gids, int32(v)) - } - case "Threads": - v, err := strconv.ParseInt(value, 10, 32) - if err != nil { - return err - } - p.numThreads = int32(v) - case "voluntary_ctxt_switches": - v, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return err - } - p.numCtxSwitches.Voluntary = v - case "nonvoluntary_ctxt_switches": - v, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return err - } - p.numCtxSwitches.Involuntary = v - case "VmRSS": - value := strings.Trim(value, " kB") // remove last "kB" - v, err := strconv.ParseUint(value, 10, 64) - if err != nil { - return err - } - p.memInfo.RSS = v * 1024 - case "VmSize": - value := strings.Trim(value, " kB") // remove last "kB" - v, err := strconv.ParseUint(value, 10, 64) - if err != nil { - return err - } - p.memInfo.VMS = v * 1024 - case "VmSwap": - value := strings.Trim(value, " kB") // remove last "kB" - v, err := strconv.ParseUint(value, 10, 64) - if err != nil { - return err - } - p.memInfo.Swap = v * 1024 } - } return nil }