diff options
Diffstat (limited to 'vendor/github.com/keybase/go-ps')
-rw-r--r-- | vendor/github.com/keybase/go-ps/.gitignore | 1 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/.pre-commit-config.yaml | 10 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/.travis.yml | 11 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/LICENSE.md | 44 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/README.md | 31 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/appveyor.yml | 31 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/darwincgo/empty.go | 1 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/darwincgo/process_darwin.c | 87 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/darwincgo/process_darwin.go | 84 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/process.go | 75 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/process_darwin.go | 31 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/process_freebsd.go | 269 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/process_openbsd.go | 302 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/process_unix.go | 144 | ||||
-rw-r--r-- | vendor/github.com/keybase/go-ps/process_windows.go | 196 |
15 files changed, 1317 insertions, 0 deletions
diff --git a/vendor/github.com/keybase/go-ps/.gitignore b/vendor/github.com/keybase/go-ps/.gitignore new file mode 100644 index 0000000..a977916 --- /dev/null +++ b/vendor/github.com/keybase/go-ps/.gitignore @@ -0,0 +1 @@ +.vagrant/ diff --git a/vendor/github.com/keybase/go-ps/.pre-commit-config.yaml b/vendor/github.com/keybase/go-ps/.pre-commit-config.yaml new file mode 100644 index 0000000..b87b62d --- /dev/null +++ b/vendor/github.com/keybase/go-ps/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +- repo: https://github.com/gabriel/pre-commit-golang + sha: c02a81d85a5295886022b8106c367518e6c3760e + hooks: + - id: go-fmt + - id: go-metalinter + args: + - --deadline=60s + - --vendor + - --cyclo-over=20 + - --dupl-threshold=100 diff --git a/vendor/github.com/keybase/go-ps/.travis.yml b/vendor/github.com/keybase/go-ps/.travis.yml new file mode 100644 index 0000000..f5b919d --- /dev/null +++ b/vendor/github.com/keybase/go-ps/.travis.yml @@ -0,0 +1,11 @@ +language: go +go: + - tip +os: + - linux + - osx +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover +script: + - $HOME/gopath/bin/goveralls -service=travis-ci diff --git a/vendor/github.com/keybase/go-ps/LICENSE.md b/vendor/github.com/keybase/go-ps/LICENSE.md new file mode 100644 index 0000000..83eb91b --- /dev/null +++ b/vendor/github.com/keybase/go-ps/LICENSE.md @@ -0,0 +1,44 @@ +The MIT License (MIT) + +Copyright (c) 2014 Mitchell Hashimoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +The MIT License (MIT) + +Copyright (c) 2015 Keybase + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/keybase/go-ps/README.md b/vendor/github.com/keybase/go-ps/README.md new file mode 100644 index 0000000..3d5762a --- /dev/null +++ b/vendor/github.com/keybase/go-ps/README.md @@ -0,0 +1,31 @@ +# Process List Library for Go + +[![Build Status](https://travis-ci.org/keybase/go-ps.svg?branch=master)](https://travis-ci.org/keybase/go-ps) +[![Build Status](https://ci.appveyor.com/api/projects/status/github/keybase/go-ps?branch=master&svg=true)](https://ci.appveyor.com/project/keybase/go-ps) +[![Coverage Status](https://coveralls.io/repos/github/keybase/go-ps/badge.svg?branch=master)](https://coveralls.io/github/keybase/go-ps?branch=master) +[![GoDoc](https://godoc.org/github.com/keybase/go-ps?status.svg)](https://godoc.org/github.com/keybase/go-ps) + + +go-ps is a library for Go that implements OS-specific APIs to list and +manipulate processes in a platform-safe way. The library can find and +list processes on Linux, Mac OS X, and Windows. + +If you're new to Go, this library has a good amount of advanced Go educational +value as well. It uses some advanced features of Go: build tags, accessing +DLL methods for Windows, cgo for Darwin, etc. + +How it works: + + * **Darwin** uses `sysctl` and `proc_listpids` (for the path) to retrieve the process table, via cgo. + * **Unix** uses the procfs at `/proc` to inspect the process tree. + * **Windows** uses the Windows API, and methods such as + `CreateToolhelp32Snapshot` to get a point-in-time snapshot of + the process table. + +## Installation + +Install using standard `go get`: + +``` +$ go get github.com/keybase/go-ps +``` diff --git a/vendor/github.com/keybase/go-ps/appveyor.yml b/vendor/github.com/keybase/go-ps/appveyor.yml new file mode 100644 index 0000000..59a98ac --- /dev/null +++ b/vendor/github.com/keybase/go-ps/appveyor.yml @@ -0,0 +1,31 @@ +# environment variables +environment: + global: + GOPATH: c:\work\ + +# clone path +clone_folder: c:\work\src\github.com\keybase\go-ps + +# build platform, i.e. x86, x64, Any CPU. This setting is optional. +#platform: Any CPU + +# scripts to run before build +before_build: + +# scripts to run after build +after_build: + +# to run your custom scripts instead of automatic MSBuild +build_script: + - go version + - go build + - go get github.com/stretchr/testify/assert + - go get github.com/stretchr/testify/require + - go test -short -v + - go test -short -race -v + +# to disable automatic tests +test: off + +# to disable deployment +deploy: off diff --git a/vendor/github.com/keybase/go-ps/darwincgo/empty.go b/vendor/github.com/keybase/go-ps/darwincgo/empty.go new file mode 100644 index 0000000..bc315c6 --- /dev/null +++ b/vendor/github.com/keybase/go-ps/darwincgo/empty.go @@ -0,0 +1 @@ +package darwincgo diff --git a/vendor/github.com/keybase/go-ps/darwincgo/process_darwin.c b/vendor/github.com/keybase/go-ps/darwincgo/process_darwin.c new file mode 100644 index 0000000..610a8ef --- /dev/null +++ b/vendor/github.com/keybase/go-ps/darwincgo/process_darwin.c @@ -0,0 +1,87 @@ +// +build darwin + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <strings.h> +#include <libproc.h> +#include <unistd.h> +#include <sys/sysctl.h> + +// This is declared in process_darwin.go +extern void goDarwinAppendProc(pid_t, pid_t, char *); +extern void goDarwinSetPath(pid_t, char *); + +// darwinProcesses loads the process table and calls the exported Go function to +// insert the data back into the Go space. +// +// This function is implemented in C because while it would technically +// be possible to do this all in Go, I didn't want to go spelunking through +// header files to get all the structures properly. It is much easier to just +// call it in C and be done with it. +int darwinProcesses() { + int err = 0; + int i = 0; + static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; + size_t length = 0; + struct kinfo_proc *result = NULL; + size_t resultCount = 0; + + // Get the length first + err = sysctl((int*)name, (sizeof(name) / sizeof(*name)) - 1, + NULL, &length, NULL, 0); + if (err != 0) { + goto ERREXIT; + } + + // Allocate the appropriate sized buffer to read the process list + result = malloc(length); + + // Call sysctl again with our buffer to fill it with the process list + err = sysctl((int*)name, (sizeof(name) / sizeof(*name)) - 1, + result, &length, + NULL, 0); + if (err != 0) { + goto ERREXIT; + } + + resultCount = length / sizeof(struct kinfo_proc); + for (i = 0; i < resultCount; i++) { + struct kinfo_proc *single = &result[i]; + goDarwinAppendProc( + single->kp_proc.p_pid, + single->kp_eproc.e_ppid, + single->kp_proc.p_comm); + } + +ERREXIT: + if (result != NULL) { + free(result); + } + + if (err != 0) { + return errno; + } + return 0; +} + +// darwinProcessPaths looks up paths for process pids +void darwinProcessPaths() { + int pid_buf_size = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); + int pid_count = pid_buf_size / sizeof(pid_t); + + pid_t* pids = malloc(pid_buf_size); + bzero(pids, pid_buf_size); + + proc_listpids(PROC_ALL_PIDS, 0, pids, pid_buf_size); + char path_buffer[PROC_PIDPATHINFO_MAXSIZE]; + + for (int i=0; i < pid_count; i++) { + if (pids[i] == 0) break; + bzero(path_buffer, PROC_PIDPATHINFO_MAXSIZE); + if (proc_pidpath(pids[i], path_buffer, sizeof(path_buffer)) > 0) { + goDarwinSetPath(pids[i], path_buffer); + } + } + free(pids); +} diff --git a/vendor/github.com/keybase/go-ps/darwincgo/process_darwin.go b/vendor/github.com/keybase/go-ps/darwincgo/process_darwin.go new file mode 100644 index 0000000..ab9edf4 --- /dev/null +++ b/vendor/github.com/keybase/go-ps/darwincgo/process_darwin.go @@ -0,0 +1,84 @@ +// +build darwin + +package darwincgo + +/* +#include <stdio.h> +#include <errno.h> +#include <libproc.h> +extern int darwinProcesses(); +extern void darwinProcessPaths(); +*/ +import "C" + +import ( + "path/filepath" + "sync" +) + +// This lock is what verifies that C calling back into Go is only +// modifying data once at a time. +var darwinLock sync.Mutex +var darwinProcsByPID map[int]*DarwinProcess + +// DarwinProcess is process definition for OS X +type DarwinProcess struct { + pid int + ppid int + path string +} + +// Pid returns process id +func (p *DarwinProcess) Pid() int { + return p.pid +} + +// PPid returns parent process id +func (p *DarwinProcess) PPid() int { + return p.ppid +} + +// Executable returns process executable name +func (p *DarwinProcess) Executable() string { + path, _ := p.Path() + return filepath.Base(path) +} + +// Path returns path to process executable +func (p *DarwinProcess) Path() (string, error) { + return p.path, nil +} + +//export goDarwinAppendProc +func goDarwinAppendProc(pid C.pid_t, ppid C.pid_t, comm *C.char) { + proc := &DarwinProcess{ + pid: int(pid), + ppid: int(ppid), + } + darwinProcsByPID[proc.pid] = proc +} + +//export goDarwinSetPath +func goDarwinSetPath(pid C.pid_t, comm *C.char) { + if proc, ok := darwinProcsByPID[int(pid)]; ok && proc != nil { + proc.path = C.GoString(comm) + } +} + +// ProcessMap returns a map of processes for the main library package. +func ProcessMap() (map[int]*DarwinProcess, error) { + darwinLock.Lock() + defer darwinLock.Unlock() + darwinProcsByPID = make(map[int]*DarwinProcess) + + // To ignore deadcode warnings for exported functions + _ = goDarwinAppendProc + _ = goDarwinSetPath + + // TODO: Investigate why darwinProcesses returns error even if process list + // succeeds + C.darwinProcesses() + C.darwinProcessPaths() + + return darwinProcsByPID, nil +} diff --git a/vendor/github.com/keybase/go-ps/process.go b/vendor/github.com/keybase/go-ps/process.go new file mode 100644 index 0000000..042cd1b --- /dev/null +++ b/vendor/github.com/keybase/go-ps/process.go @@ -0,0 +1,75 @@ +// Package ps provides an API for finding and listing processes in a +// platform-agnostic way. +// +// NOTE: If you're reading these docs online via GoDocs or some other system, +// you might only see the Unix docs. This project makes heavy use of +// platform-specific implementations. We recommend reading the source if you +// are interested. +package ps + +import "fmt" + +// Process is the generic interface that is implemented on every platform +// and provides common operations for processes. +type Process interface { + // Pid is the process ID for this process. + Pid() int + + // PPid is the parent process ID for this process. + PPid() int + + // Executable name running this process. This is not a path to the + // executable. + Executable() string + + // Path is full path to the executable. The path may be unavailable if the + // exectuable was deleted from the system while it was still running. + Path() (string, error) +} + +type processesFn func() ([]Process, error) + +// Processes returns all processes. +// +// This of course will be a point-in-time snapshot of when this method was +// called. Some operating systems don't provide snapshot capability of the +// process table, in which case the process table returned might contain +// ephemeral entities that happened to be running when this was called. +func Processes() ([]Process, error) { + return processes() +} + +// FindProcess looks up a single process by pid. +// This may require a full process listing depending on the platform, so +// consider using os.FindProcess instead. +// Process will be nil and error will be nil if a matching process is not found. +func FindProcess(pid int) (Process, error) { + return findProcess(pid) +} + +type matchFn func(Process) bool + +// findProcessesWithFn finds processes using match function. +// If max is != 0, then we will return that max number of processes. +func findProcessesWithFn(processesFn processesFn, matchFn matchFn, max int) ([]Process, error) { + processes, err := processesFn() + if err != nil { + return nil, fmt.Errorf("Error listing processes: %s", err) + } + if processes == nil { + return nil, nil + } + procs := []Process{} + for _, p := range processes { + if matchFn(p) { + procs = append(procs, p) + } + if max != 0 && len(procs) >= max { + break + } + } + return procs, nil +} + +// Avoid linting error +var _ = findProcessesWithFn diff --git a/vendor/github.com/keybase/go-ps/process_darwin.go b/vendor/github.com/keybase/go-ps/process_darwin.go new file mode 100644 index 0000000..02cfa79 --- /dev/null +++ b/vendor/github.com/keybase/go-ps/process_darwin.go @@ -0,0 +1,31 @@ +// +build darwin + +package ps + +import ( + "github.com/keybase/go-ps/darwincgo" +) + +func findProcess(pid int) (Process, error) { + m, err := darwincgo.ProcessMap() + if err != nil { + return nil, err + } + p := m[pid] + if p == nil { + return nil, nil + } + return p, nil +} + +func processes() ([]Process, error) { + m, err := darwincgo.ProcessMap() + if err != nil { + return nil, err + } + ps := make([]Process, 0, len(m)) + for _, dp := range m { + ps = append(ps, dp) + } + return ps, nil +} diff --git a/vendor/github.com/keybase/go-ps/process_freebsd.go b/vendor/github.com/keybase/go-ps/process_freebsd.go new file mode 100644 index 0000000..33942c8 --- /dev/null +++ b/vendor/github.com/keybase/go-ps/process_freebsd.go @@ -0,0 +1,269 @@ +// +build freebsd,amd64 + +package ps + +import ( + "bytes" + "encoding/binary" + "fmt" + "syscall" + "unsafe" +) + +// copied from sys/sysctl.h +const ( + CTL_KERN = 1 // "high kernel": proc, limits + KERN_PROC = 14 // struct: process entries + KERN_PROC_PID = 1 // by process id + KERN_PROC_PROC = 8 // only return procs + KERN_PROC_PATHNAME = 12 // path to executable +) + +// copied from sys/user.h +type Kinfo_proc struct { + Ki_structsize int32 + Ki_layout int32 + Ki_args int64 + Ki_paddr int64 + Ki_addr int64 + Ki_tracep int64 + Ki_textvp int64 + Ki_fd int64 + Ki_vmspace int64 + Ki_wchan int64 + Ki_pid int32 + Ki_ppid int32 + Ki_pgid int32 + Ki_tpgid int32 + Ki_sid int32 + Ki_tsid int32 + Ki_jobc [2]byte + Ki_spare_short1 [2]byte + Ki_tdev int32 + Ki_siglist [16]byte + Ki_sigmask [16]byte + Ki_sigignore [16]byte + Ki_sigcatch [16]byte + Ki_uid int32 + Ki_ruid int32 + Ki_svuid int32 + Ki_rgid int32 + Ki_svgid int32 + Ki_ngroups [2]byte + Ki_spare_short2 [2]byte + Ki_groups [64]byte + Ki_size int64 + Ki_rssize int64 + Ki_swrss int64 + Ki_tsize int64 + Ki_dsize int64 + Ki_ssize int64 + Ki_xstat [2]byte + Ki_acflag [2]byte + Ki_pctcpu int32 + Ki_estcpu int32 + Ki_slptime int32 + Ki_swtime int32 + Ki_cow int32 + Ki_runtime int64 + Ki_start [16]byte + Ki_childtime [16]byte + Ki_flag int64 + Ki_kiflag int64 + Ki_traceflag int32 + Ki_stat [1]byte + Ki_nice [1]byte + Ki_lock [1]byte + Ki_rqindex [1]byte + Ki_oncpu [1]byte + Ki_lastcpu [1]byte + Ki_ocomm [17]byte + Ki_wmesg [9]byte + Ki_login [18]byte + Ki_lockname [9]byte + Ki_comm [20]byte + Ki_emul [17]byte + Ki_sparestrings [68]byte + Ki_spareints [36]byte + Ki_cr_flags int32 + Ki_jid int32 + Ki_numthreads int32 + Ki_tid int32 + Ki_pri int32 + Ki_rusage [144]byte + Ki_rusage_ch [144]byte + Ki_pcb int64 + Ki_kstack int64 + Ki_udata int64 + Ki_tdaddr int64 + Ki_spareptrs [48]byte + Ki_spareint64s [96]byte + Ki_sflag int64 + Ki_tdflags int64 +} + +// 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 +} + +// 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 { + return p.binary +} + +// Path returns path to process executable +func (p *UnixProcess) Path() (string, error) { + return "", fmt.Errorf("Unsupported") +} + +// Refresh reloads all the data associated with this process. +func (p *UnixProcess) Refresh() error { + + mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PID, int32(p.pid)} + + buf, length, err := call_syscall(mib) + if err != nil { + return err + } + proc_k := Kinfo_proc{} + if length != uint64(unsafe.Sizeof(proc_k)) { + return err + } + + k, err := parse_kinfo_proc(buf) + if err != nil { + return err + } + + p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k) + return nil +} + +func copy_params(k *Kinfo_proc) (int, int, int, string) { + n := -1 + for i, b := range k.Ki_comm { + if b == 0 { + break + } + n = i + 1 + } + comm := string(k.Ki_comm[:n]) + + return int(k.Ki_ppid), int(k.Ki_pgid), int(k.Ki_sid), comm +} + +func findProcess(pid int) (Process, error) { + mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, int32(pid)} + + _, _, err := call_syscall(mib) + if err != nil { + return nil, err + } + + return newUnixProcess(pid) +} + +func processes() ([]Process, error) { + results := make([]Process, 0, 50) + + mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0} + buf, length, err := call_syscall(mib) + if err != nil { + return results, err + } + + // get kinfo_proc size + k := Kinfo_proc{} + procinfo_len := int(unsafe.Sizeof(k)) + count := int(length / uint64(procinfo_len)) + + // parse buf to procs + for i := 0; i < count; i++ { + b := buf[i*procinfo_len : i*procinfo_len+procinfo_len] + k, err := parse_kinfo_proc(b) + if err != nil { + continue + } + p, err := newUnixProcess(int(k.Ki_pid)) + if err != nil { + continue + } + p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k) + + results = append(results, p) + } + + return results, nil +} + +func parse_kinfo_proc(buf []byte) (Kinfo_proc, error) { + var k Kinfo_proc + br := bytes.NewReader(buf) + err := binary.Read(br, binary.LittleEndian, &k) + if err != nil { + return k, err + } + + return k, nil +} + +func call_syscall(mib []int32) ([]byte, uint64, error) { + miblen := uint64(len(mib)) + + // get required buffer size + length := uint64(0) + _, _, err := syscall.RawSyscall6( + syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(miblen), + 0, + uintptr(unsafe.Pointer(&length)), + 0, + 0) + if err != 0 { + b := make([]byte, 0) + return b, length, err + } + if length == 0 { + b := make([]byte, 0) + return b, length, err + } + // get proc info itself + buf := make([]byte, length) + _, _, err = syscall.RawSyscall6( + syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(miblen), + uintptr(unsafe.Pointer(&buf[0])), + uintptr(unsafe.Pointer(&length)), + 0, + 0) + if err != 0 { + return buf, length, err + } + + return buf, length, nil +} + +func newUnixProcess(pid int) (*UnixProcess, error) { + p := &UnixProcess{pid: pid} + return p, p.Refresh() +} diff --git a/vendor/github.com/keybase/go-ps/process_openbsd.go b/vendor/github.com/keybase/go-ps/process_openbsd.go new file mode 100644 index 0000000..51c446d --- /dev/null +++ b/vendor/github.com/keybase/go-ps/process_openbsd.go @@ -0,0 +1,302 @@ +// +build openbsd + +package ps + +import ( + "bytes" + "encoding/binary" + "fmt" + "syscall" + "unsafe" +) + +// copied from sys/sysctl.h +const ( + CTL_KERN = 1 + KERN_PROC = 66 + KERN_PROC_PID = 1 + KERN_PROC_ARGS = 55 + KERN_PROC_ARGV = 1 + KERN_PROC_ALL = 0 +) + +/* Generated via cgo: + +$ cat /tmp/gen_defs.go +// +build ignore +package ps +// #include <sys/types.h> +// #include <sys/sysctl.h> +import "C" + +type Kinfo_proc C.struct_kinfo_proc + +$ go tool cgo -godefs temp.go + +*/ + +type Kinfo_proc struct { + Ki_forw uint64 + Ki_back uint64 + Ki_paddr uint64 + Ki_addr uint64 + Ki_fd uint64 + Ki_stats uint64 + Ki_limit uint64 + Ki_vmspace uint64 + Ki_sigacts uint64 + Ki_sess uint64 + Ki_tsess uint64 + Ki_ru uint64 + Ki_eflag int32 + Ki_exitsig int32 + Ki_flag int32 + Ki_pid int32 + Ki_ppid int32 + Ki_sid int32 + Ki_x_pgid int32 + Ki_tpgid int32 + Ki_uid uint32 + Ki_ruid uint32 + Ki_gid uint32 + Ki_rgid uint32 + Ki_groups [16]uint32 + Ki_ngroups int16 + Ki_jobc int16 + Ki_tdev uint32 + Ki_estcpu uint32 + Ki_rtime_sec uint32 + Ki_rtime_usec uint32 + Ki_cpticks int32 + Ki_pctcpu uint32 + Ki_swtime uint32 + Ki_slptime uint32 + Ki_schedflags int32 + Ki_uticks uint64 + Ki_sticks uint64 + Ki_iticks uint64 + Ki_tracep uint64 + Ki_traceflag int32 + Ki_holdcnt int32 + Ki_siglist int32 + Ki_sigmask uint32 + Ki_sigignore uint32 + Ki_sigcatch uint32 + Ki_stat int8 + Ki_priority uint8 + Ki_usrpri uint8 + Ki_nice uint8 + Ki_xstat uint16 + Ki_acflag uint16 + //Ki_comm [24]int8 + Ki_comm [20]byte + Ki_wmesg [8]int8 + Ki_wchan uint64 + Ki_login [32]int8 + Ki_vm_rssize int32 + Ki_vm_tsize int32 + Ki_vm_dsize int32 + Ki_vm_ssize int32 + Ki_uvalid int64 + Ki_ustart_sec uint64 + Ki_ustart_usec uint32 + Ki_uutime_sec uint32 + Ki_uutime_usec uint32 + Ki_ustime_sec uint32 + Ki_ustime_usec uint32 + Ki_pad_cgo_0 [4]byte + Ki_uru_maxrss uint64 + Ki_uru_ixrss uint64 + Ki_uru_idrss uint64 + Ki_uru_isrss uint64 + Ki_uru_minflt uint64 + Ki_uru_majflt uint64 + Ki_uru_nswap uint64 + Ki_uru_inblock uint64 + Ki_uru_oublock uint64 + Ki_uru_msgsnd uint64 + Ki_uru_msgrcv uint64 + Ki_uru_nsignals uint64 + Ki_uru_nvcsw uint64 + Ki_uru_nivcsw uint64 + Ki_uctime_sec uint32 + Ki_uctime_usec uint32 + Ki_psflags int32 + Ki_spare int32 + Ki_svuid uint32 + Ki_svgid uint32 + Ki_emul [8]int8 + Ki_rlim_rss_cur uint64 + Ki_cpuid uint64 + Ki_vm_map_size uint64 + Ki_tid int32 + Ki_rtableid uint32 +} + +var proc_k_size = unsafe.Sizeof(Kinfo_proc{}) + +// 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 +} + +// 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 { + return p.binary +} + +// Path returns path to process executable +func (p *UnixProcess) Path() (string, error) { + // On OpenBSD we don't have the actual path of a binary, the next + // best thing we can do is walk $PATH to hopefully find the binary. + // More info here: https://github.com/kardianos/osext/commit/b4814f465fb1f92d46e37f7ef84d732ece7c3e3a + return "", fmt.Errorf("Unsupported") +} + +// Refresh reloads all the data associated with this process. +func (p *UnixProcess) Refresh() error { + mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PID, int32(p.pid), int32(proc_k_size), 1} + + buf, length, err := call_syscall(mib) + if err != nil { + return err + } + if length != uint64(proc_k_size) { + return err + } + + k, err := parse_kinfo_proc(buf) + if err != nil { + return err + } + + p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k) + return nil +} + +func copy_params(k *Kinfo_proc) (int, int, int, string) { + n := -1 + for i, b := range k.Ki_comm { + if b == 0 { + break + } + n = i + 1 + } + comm := string(k.Ki_comm[:n]) + + return int(k.Ki_ppid), int(k.Ki_x_pgid), int(k.Ki_sid), comm +} + +func findProcess(pid int) (Process, error) { + mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PID, int32(pid), int32(proc_k_size), 1} + + _, _, err := call_syscall(mib) + if err != nil { + return nil, err + } + + return newUnixProcess(pid) +} + +func processes() ([]Process, error) { + results := make([]Process, 0, 50) + + mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, int32(proc_k_size), 400} + buf, length, err := call_syscall(mib) + if err != nil { + return results, err + } + + // get kinfo_proc size + procinfo_len := int(proc_k_size) + count := int(length / uint64(proc_k_size)) + + // parse buf to procs + for i := 0; i < count; i++ { + b := buf[i*procinfo_len : i*procinfo_len+procinfo_len] + k, err := parse_kinfo_proc(b) + if err != nil { + continue + } + p, err := newUnixProcess(int(k.Ki_pid)) + if err != nil { + continue + } + p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k) + + results = append(results, p) + } + + return results, nil +} + +func parse_kinfo_proc(buf []byte) (Kinfo_proc, error) { + var k Kinfo_proc + br := bytes.NewReader(buf) + err := binary.Read(br, binary.LittleEndian, &k) + if err != nil { + return k, err + } + + return k, nil +} + +func call_syscall(mib []int32) ([]byte, uint64, error) { + miblen := uint64(len(mib)) + + // get required buffer size + length := uint64(0) + _, _, err := syscall.RawSyscall6( + syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(miblen), + 0, + uintptr(unsafe.Pointer(&length)), + 0, + 0) + if err != 0 { + b := make([]byte, 0) + return b, length, err + } + if length == 0 { + b := make([]byte, 0) + return b, length, err + } + // get proc info itself + buf := make([]byte, length) + _, _, err = syscall.RawSyscall6( + syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(miblen), + uintptr(unsafe.Pointer(&buf[0])), + uintptr(unsafe.Pointer(&length)), + 0, + 0) + if err != 0 { + return buf, length, err + } + + return buf, length, nil +} + +func newUnixProcess(pid int) (*UnixProcess, error) { + p := &UnixProcess{pid: pid} + return p, p.Refresh() +} 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() +} diff --git a/vendor/github.com/keybase/go-ps/process_windows.go b/vendor/github.com/keybase/go-ps/process_windows.go new file mode 100644 index 0000000..e4d89e3 --- /dev/null +++ b/vendor/github.com/keybase/go-ps/process_windows.go @@ -0,0 +1,196 @@ +// +build windows + +package ps + +import ( + "fmt" + "syscall" + "unsafe" +) + +// Windows API functions +var ( + modKernel32 = syscall.NewLazyDLL("kernel32.dll") + procCloseHandle = modKernel32.NewProc("CloseHandle") + procCreateToolhelp32Snapshot = modKernel32.NewProc("CreateToolhelp32Snapshot") + procProcess32First = modKernel32.NewProc("Process32FirstW") + procProcess32Next = modKernel32.NewProc("Process32NextW") + procModule32First = modKernel32.NewProc("Module32FirstW") + procModule32Next = modKernel32.NewProc("Module32NextW") +) + +// Some constants from the Windows API +const ( + ERROR_NO_MORE_FILES = 0x12 + MAX_PATH = 260 + MAX_MODULE_NAME32 = 255 +) + +type PROCESSENTRY32 struct { + Size uint32 + CntUsage uint32 + ProcessID uint32 + DefaultHeapID uintptr + ModuleID uint32 + CntThreads uint32 + ParentProcessID uint32 + PriorityClassBase int32 + Flags uint32 + ExeFile [MAX_PATH]uint16 +} + +// WindowsProcess is an implementation of Process for Windows. +type WindowsProcess struct { + pid int + ppid int + exe string +} + +// Pid returns process id +func (p *WindowsProcess) Pid() int { + return p.pid +} + +// PPid returns parent process id +func (p *WindowsProcess) PPid() int { + return p.ppid +} + +// Executable returns process executable name +func (p *WindowsProcess) Executable() string { + return p.exe +} + +// Path returns path to process executable +func (p *WindowsProcess) Path() (string, error) { + processModules, err := modules(p.pid) + if err != nil { + return "", err + } + if len(processModules) == 0 { + return "", fmt.Errorf("No modules found for process") + } + return processModules[0].path, nil +} + +func ptrToString(c []uint16) string { + i := 0 + for { + if c[i] == 0 { + return syscall.UTF16ToString(c[:i]) + } + i++ + } +} + +func newWindowsProcess(e *PROCESSENTRY32) *WindowsProcess { + return &WindowsProcess{ + pid: int(e.ProcessID), + ppid: int(e.ParentProcessID), + exe: ptrToString(e.ExeFile[:]), + } +} + +func findProcess(pid int) (Process, error) { + return findProcessWithFn(processes, pid) +} + +func findProcessWithFn(processesFn processesFn, pid int) (Process, error) { + ps, err := processesFn() + if err != nil { + return nil, fmt.Errorf("Error listing processes: %s", err) + } + + for _, p := range ps { + if p.Pid() == pid { + return p, nil + } + } + + return nil, nil +} + +func processes() ([]Process, error) { + handle, _, _ := procCreateToolhelp32Snapshot.Call( + 0x00000002, + 0) + if handle < 0 { + return nil, syscall.GetLastError() + } + defer procCloseHandle.Call(handle) + + var entry PROCESSENTRY32 + entry.Size = uint32(unsafe.Sizeof(entry)) + ret, _, _ := procProcess32First.Call(handle, uintptr(unsafe.Pointer(&entry))) + if ret == 0 { + return nil, fmt.Errorf("Error retrieving process info.") + } + + results := make([]Process, 0, 50) + for { + results = append(results, newWindowsProcess(&entry)) + + ret, _, _ := procProcess32Next.Call(handle, uintptr(unsafe.Pointer(&entry))) + if ret == 0 { + break + } + } + + return results, nil +} + +// MODULEENTRY32 is the Windows API structure that contains a modules's +// information. +type MODULEENTRY32 struct { + Size uint32 + ModuleID uint32 + ProcessID uint32 + GlblcntUsage uint32 + ProccntUsage uint32 + ModBaseAddr *uint8 + ModBaseSize uint32 + HModule uintptr + SzModule [MAX_MODULE_NAME32 + 1]uint16 + SzExePath [MAX_PATH]uint16 +} + +type windowsModule struct { + name string + path string +} + +func newWindowsModule(e *MODULEENTRY32) windowsModule { + return windowsModule{ + name: ptrToString(e.SzModule[:]), + path: ptrToString(e.SzExePath[:]), + } +} + +func modules(pid int) ([]windowsModule, error) { + handle, _, _ := procCreateToolhelp32Snapshot.Call( + 0x00000008, // TH32CS_SNAPMODULE + uintptr(uint32(pid))) + if handle < 0 { + return nil, syscall.GetLastError() + } + defer procCloseHandle.Call(handle) + + var entry MODULEENTRY32 + entry.Size = uint32(unsafe.Sizeof(entry)) + ret, _, _ := procModule32First.Call(handle, uintptr(unsafe.Pointer(&entry))) + if ret == 0 { + return nil, fmt.Errorf("Error retrieving module info") + } + + results := make([]windowsModule, 0, 50) + for { + results = append(results, newWindowsModule(&entry)) + + ret, _, _ := procModule32Next.Call(handle, uintptr(unsafe.Pointer(&entry))) + if ret == 0 { + break + } + } + + return results, nil +} |