diff options
Diffstat (limited to 'vendor/github.com/keybase/go-ps/process_unix.go')
-rw-r--r-- | vendor/github.com/keybase/go-ps/process_unix.go | 144 |
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() +} |