summaryrefslogtreecommitdiff
path: root/vendor/github.com/keybase/go-ps/process_unix.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/keybase/go-ps/process_unix.go')
-rw-r--r--vendor/github.com/keybase/go-ps/process_unix.go144
1 files changed, 144 insertions, 0 deletions
diff --git a/vendor/github.com/keybase/go-ps/process_unix.go b/vendor/github.com/keybase/go-ps/process_unix.go
new file mode 100644
index 0000000..8c89b7e
--- /dev/null
+++ b/vendor/github.com/keybase/go-ps/process_unix.go
@@ -0,0 +1,144 @@
+// +build linux netbsd
+
+package ps
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+)
+
+// UnixProcess is an implementation of Process that contains Unix-specific
+// fields and information.
+type UnixProcess struct {
+ pid int
+ ppid int
+ state rune
+ pgrp int
+ sid int
+
+ binary string // binary name might be truncated
+}
+
+// Pid returns process id
+func (p *UnixProcess) Pid() int {
+ return p.pid
+}
+
+// PPid returns parent process id
+func (p *UnixProcess) PPid() int {
+ return p.ppid
+}
+
+// Executable returns process executable name
+func (p *UnixProcess) Executable() string {
+ path, err := p.Path()
+ if err != nil {
+ // Fall back to binary name which might be truncated
+ return p.binary
+ }
+ return filepath.Base(path)
+}
+
+// Path returns path to process executable
+func (p *UnixProcess) Path() (string, error) {
+ return filepath.EvalSymlinks(fmt.Sprintf("/proc/%d/exe", p.pid))
+}
+
+// Refresh reloads all the data associated with this process.
+func (p *UnixProcess) Refresh() error {
+ statPath := fmt.Sprintf("/proc/%d/stat", p.pid)
+ dataBytes, err := ioutil.ReadFile(statPath)
+ if err != nil {
+ return err
+ }
+
+ // First, parse out the image name
+ data := string(dataBytes)
+ binStart := strings.IndexRune(data, '(') + 1
+ binEnd := strings.IndexRune(data[binStart:], ')')
+ p.binary = data[binStart : binStart+binEnd]
+
+ // Move past the image name and start parsing the rest
+ // The name here might not be the full name
+ data = data[binStart+binEnd+2:]
+ _, err = fmt.Sscanf(data,
+ "%c %d %d %d",
+ &p.state,
+ &p.ppid,
+ &p.pgrp,
+ &p.sid)
+
+ return err
+}
+
+func findProcess(pid int) (Process, error) {
+ dir := fmt.Sprintf("/proc/%d", pid)
+ _, err := os.Stat(dir)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, nil
+ }
+
+ return nil, err
+ }
+
+ return newUnixProcess(pid)
+}
+
+func processes() ([]Process, error) {
+ d, err := os.Open("/proc")
+ if err != nil {
+ return nil, err
+ }
+ defer d.Close()
+
+ results := make([]Process, 0, 50)
+ for {
+ fis, err := d.Readdir(10)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ for _, fi := range fis {
+ // We only care about directories, since all pids are dirs
+ if !fi.IsDir() {
+ continue
+ }
+
+ // We only care if the name starts with a numeric
+ name := fi.Name()
+ if name[0] < '0' || name[0] > '9' {
+ continue
+ }
+
+ // From this point forward, any errors we just ignore, because
+ // it might simply be that the process doesn't exist anymore.
+ pid, err := strconv.ParseInt(name, 10, 0)
+ if err != nil {
+ continue
+ }
+
+ p, err := newUnixProcess(int(pid))
+ if err != nil {
+ continue
+ }
+
+ results = append(results, p)
+ }
+ }
+
+ return results, nil
+}
+
+func newUnixProcess(pid int) (*UnixProcess, error) {
+ p := &UnixProcess{pid: pid}
+ return p, p.Refresh()
+}