AJ ONeal
há 5 anos
26 ficheiros modificados com 1383 adições e 61 eliminações
@ -1,10 +1,23 @@ |
|||
package runner |
|||
|
|||
import ( |
|||
"fmt" |
|||
"os/exec" |
|||
"strconv" |
|||
"syscall" |
|||
) |
|||
|
|||
func backgroundCmd(cmd *exec.Cmd) { |
|||
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} |
|||
} |
|||
|
|||
func kill(pid int) error { |
|||
// Kill the whole processes tree (all children and grandchildren)
|
|||
cmd := exec.Command("taskkill", "/pid", strconv.Itoa(pid), "/T", "/F") |
|||
b, err := cmd.CombinedOutput() |
|||
if nil != err { |
|||
return fmt.Errorf("%s: %s", err.Error(), string(b)) |
|||
} |
|||
|
|||
return nil |
|||
} |
|||
|
@ -0,0 +1 @@ |
|||
.vagrant/ |
@ -0,0 +1,4 @@ |
|||
language: go |
|||
|
|||
go: |
|||
- 1.2.1 |
@ -0,0 +1,21 @@ |
|||
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. |
@ -0,0 +1,34 @@ |
|||
# Process List Library for Go |
|||
|
|||
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, Solaris, 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 the `sysctl` syscall to retrieve the process table. |
|||
* **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/mitchellh/go-ps |
|||
... |
|||
``` |
|||
|
|||
## TODO |
|||
|
|||
Want to contribute? Here is a short TODO list of things that aren't |
|||
implemented for this library that would be nice: |
|||
|
|||
* FreeBSD support |
|||
* Plan9 support |
@ -0,0 +1,43 @@ |
|||
# -*- mode: ruby -*- |
|||
# vi: set ft=ruby : |
|||
|
|||
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! |
|||
VAGRANTFILE_API_VERSION = "2" |
|||
|
|||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| |
|||
config.vm.box = "chef/ubuntu-12.04" |
|||
|
|||
config.vm.provision "shell", inline: $script |
|||
|
|||
["vmware_fusion", "vmware_workstation"].each do |p| |
|||
config.vm.provider "p" do |v| |
|||
v.vmx["memsize"] = "1024" |
|||
v.vmx["numvcpus"] = "2" |
|||
v.vmx["cpuid.coresPerSocket"] = "1" |
|||
end |
|||
end |
|||
end |
|||
|
|||
$script = <<SCRIPT |
|||
SRCROOT="/opt/go" |
|||
|
|||
# Install Go |
|||
sudo apt-get update |
|||
sudo apt-get install -y build-essential mercurial |
|||
sudo hg clone -u release https://code.google.com/p/go ${SRCROOT} |
|||
cd ${SRCROOT}/src |
|||
sudo ./all.bash |
|||
|
|||
# Setup the GOPATH |
|||
sudo mkdir -p /opt/gopath |
|||
cat <<EOF >/tmp/gopath.sh |
|||
export GOPATH="/opt/gopath" |
|||
export PATH="/opt/go/bin:\$GOPATH/bin:\$PATH" |
|||
EOF |
|||
sudo mv /tmp/gopath.sh /etc/profile.d/gopath.sh |
|||
sudo chmod 0755 /etc/profile.d/gopath.sh |
|||
|
|||
# Make sure the gopath is usable by bamboo |
|||
sudo chown -R vagrant:vagrant $SRCROOT |
|||
sudo chown -R vagrant:vagrant /opt/gopath |
|||
SCRIPT |
@ -0,0 +1,40 @@ |
|||
// 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 |
|||
|
|||
// 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 |
|||
} |
|||
|
|||
// 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.
|
|||
//
|
|||
// 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) |
|||
} |
@ -0,0 +1,138 @@ |
|||
// +build darwin
|
|||
|
|||
package ps |
|||
|
|||
import ( |
|||
"bytes" |
|||
"encoding/binary" |
|||
"syscall" |
|||
"unsafe" |
|||
) |
|||
|
|||
type DarwinProcess struct { |
|||
pid int |
|||
ppid int |
|||
binary string |
|||
} |
|||
|
|||
func (p *DarwinProcess) Pid() int { |
|||
return p.pid |
|||
} |
|||
|
|||
func (p *DarwinProcess) PPid() int { |
|||
return p.ppid |
|||
} |
|||
|
|||
func (p *DarwinProcess) Executable() string { |
|||
return p.binary |
|||
} |
|||
|
|||
func findProcess(pid int) (Process, error) { |
|||
ps, err := processes() |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
for _, p := range ps { |
|||
if p.Pid() == pid { |
|||
return p, nil |
|||
} |
|||
} |
|||
|
|||
return nil, nil |
|||
} |
|||
|
|||
func processes() ([]Process, error) { |
|||
buf, err := darwinSyscall() |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
procs := make([]*kinfoProc, 0, 50) |
|||
k := 0 |
|||
for i := _KINFO_STRUCT_SIZE; i < buf.Len(); i += _KINFO_STRUCT_SIZE { |
|||
proc := &kinfoProc{} |
|||
err = binary.Read(bytes.NewBuffer(buf.Bytes()[k:i]), binary.LittleEndian, proc) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
k = i |
|||
procs = append(procs, proc) |
|||
} |
|||
|
|||
darwinProcs := make([]Process, len(procs)) |
|||
for i, p := range procs { |
|||
darwinProcs[i] = &DarwinProcess{ |
|||
pid: int(p.Pid), |
|||
ppid: int(p.PPid), |
|||
binary: darwinCstring(p.Comm), |
|||
} |
|||
} |
|||
|
|||
return darwinProcs, nil |
|||
} |
|||
|
|||
func darwinCstring(s [16]byte) string { |
|||
i := 0 |
|||
for _, b := range s { |
|||
if b != 0 { |
|||
i++ |
|||
} else { |
|||
break |
|||
} |
|||
} |
|||
|
|||
return string(s[:i]) |
|||
} |
|||
|
|||
func darwinSyscall() (*bytes.Buffer, error) { |
|||
mib := [4]int32{_CTRL_KERN, _KERN_PROC, _KERN_PROC_ALL, 0} |
|||
size := uintptr(0) |
|||
|
|||
_, _, errno := syscall.Syscall6( |
|||
syscall.SYS___SYSCTL, |
|||
uintptr(unsafe.Pointer(&mib[0])), |
|||
4, |
|||
0, |
|||
uintptr(unsafe.Pointer(&size)), |
|||
0, |
|||
0) |
|||
|
|||
if errno != 0 { |
|||
return nil, errno |
|||
} |
|||
|
|||
bs := make([]byte, size) |
|||
_, _, errno = syscall.Syscall6( |
|||
syscall.SYS___SYSCTL, |
|||
uintptr(unsafe.Pointer(&mib[0])), |
|||
4, |
|||
uintptr(unsafe.Pointer(&bs[0])), |
|||
uintptr(unsafe.Pointer(&size)), |
|||
0, |
|||
0) |
|||
|
|||
if errno != 0 { |
|||
return nil, errno |
|||
} |
|||
|
|||
return bytes.NewBuffer(bs[0:size]), nil |
|||
} |
|||
|
|||
const ( |
|||
_CTRL_KERN = 1 |
|||
_KERN_PROC = 14 |
|||
_KERN_PROC_ALL = 0 |
|||
_KINFO_STRUCT_SIZE = 648 |
|||
) |
|||
|
|||
type kinfoProc struct { |
|||
_ [40]byte |
|||
Pid int32 |
|||
_ [199]byte |
|||
Comm [16]byte |
|||
_ [301]byte |
|||
PPid int32 |
|||
_ [84]byte |
|||
} |
@ -0,0 +1,260 @@ |
|||
// +build freebsd,amd64
|
|||
|
|||
package ps |
|||
|
|||
import ( |
|||
"bytes" |
|||
"encoding/binary" |
|||
"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 |
|||
} |
|||
|
|||
func (p *UnixProcess) Pid() int { |
|||
return p.pid |
|||
} |
|||
|
|||
func (p *UnixProcess) PPid() int { |
|||
return p.ppid |
|||
} |
|||
|
|||
func (p *UnixProcess) Executable() string { |
|||
return p.binary |
|||
} |
|||
|
|||
// 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() |
|||
} |
@ -0,0 +1,35 @@ |
|||
// +build linux
|
|||
|
|||
package ps |
|||
|
|||
import ( |
|||
"fmt" |
|||
"io/ioutil" |
|||
"strings" |
|||
) |
|||
|
|||
// 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
|
|||
data = data[binStart+binEnd+2:] |
|||
_, err = fmt.Sscanf(data, |
|||
"%c %d %d %d", |
|||
&p.state, |
|||
&p.ppid, |
|||
&p.pgrp, |
|||
&p.sid) |
|||
|
|||
return err |
|||
} |
@ -0,0 +1,96 @@ |
|||
// +build solaris
|
|||
|
|||
package ps |
|||
|
|||
import ( |
|||
"encoding/binary" |
|||
"fmt" |
|||
"os" |
|||
) |
|||
|
|||
type ushort_t uint16 |
|||
|
|||
type id_t int32 |
|||
type pid_t int32 |
|||
type uid_t int32 |
|||
type gid_t int32 |
|||
|
|||
type dev_t uint64 |
|||
type size_t uint64 |
|||
type uintptr_t uint64 |
|||
|
|||
type timestruc_t [16]byte |
|||
|
|||
// This is copy from /usr/include/sys/procfs.h
|
|||
type psinfo_t struct { |
|||
Pr_flag int32 /* process flags (DEPRECATED; do not use) */ |
|||
Pr_nlwp int32 /* number of active lwps in the process */ |
|||
Pr_pid pid_t /* unique process id */ |
|||
Pr_ppid pid_t /* process id of parent */ |
|||
Pr_pgid pid_t /* pid of process group leader */ |
|||
Pr_sid pid_t /* session id */ |
|||
Pr_uid uid_t /* real user id */ |
|||
Pr_euid uid_t /* effective user id */ |
|||
Pr_gid gid_t /* real group id */ |
|||
Pr_egid gid_t /* effective group id */ |
|||
Pr_addr uintptr_t /* address of process */ |
|||
Pr_size size_t /* size of process image in Kbytes */ |
|||
Pr_rssize size_t /* resident set size in Kbytes */ |
|||
Pr_pad1 size_t |
|||
Pr_ttydev dev_t /* controlling tty device (or PRNODEV) */ |
|||
|
|||
// Guess this following 2 ushort_t values require a padding to properly
|
|||
// align to the 64bit mark.
|
|||
Pr_pctcpu ushort_t /* % of recent cpu time used by all lwps */ |
|||
Pr_pctmem ushort_t /* % of system memory used by process */ |
|||
Pr_pad64bit [4]byte |
|||
|
|||
Pr_start timestruc_t /* process start time, from the epoch */ |
|||
Pr_time timestruc_t /* usr+sys cpu time for this process */ |
|||
Pr_ctime timestruc_t /* usr+sys cpu time for reaped children */ |
|||
Pr_fname [16]byte /* name of execed file */ |
|||
Pr_psargs [80]byte /* initial characters of arg list */ |
|||
Pr_wstat int32 /* if zombie, the wait() status */ |
|||
Pr_argc int32 /* initial argument count */ |
|||
Pr_argv uintptr_t /* address of initial argument vector */ |
|||
Pr_envp uintptr_t /* address of initial environment vector */ |
|||
Pr_dmodel [1]byte /* data model of the process */ |
|||
Pr_pad2 [3]byte |
|||
Pr_taskid id_t /* task id */ |
|||
Pr_projid id_t /* project id */ |
|||
Pr_nzomb int32 /* number of zombie lwps in the process */ |
|||
Pr_poolid id_t /* pool id */ |
|||
Pr_zoneid id_t /* zone id */ |
|||
Pr_contract id_t /* process contract */ |
|||
Pr_filler int32 /* reserved for future use */ |
|||
Pr_lwp [128]byte /* information for representative lwp */ |
|||
} |
|||
|
|||
func (p *UnixProcess) Refresh() error { |
|||
var psinfo psinfo_t |
|||
|
|||
path := fmt.Sprintf("/proc/%d/psinfo", p.pid) |
|||
fh, err := os.Open(path) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
defer fh.Close() |
|||
|
|||
err = binary.Read(fh, binary.LittleEndian, &psinfo) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
p.ppid = int(psinfo.Pr_ppid) |
|||
p.binary = toString(psinfo.Pr_fname[:], 16) |
|||
return nil |
|||
} |
|||
|
|||
func toString(array []byte, len int) string { |
|||
for i := 0; i < len; i++ { |
|||
if array[i] == 0 { |
|||
return string(array[:i]) |
|||
} |
|||
} |
|||
return string(array[:]) |
|||
} |
@ -0,0 +1,101 @@ |
|||
// +build linux solaris
|
|||
|
|||
package ps |
|||
|
|||
import ( |
|||
"fmt" |
|||
"io" |
|||
"os" |
|||
"strconv" |
|||
) |
|||
|
|||
// 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 |
|||
} |
|||
|
|||
func (p *UnixProcess) Pid() int { |
|||
return p.pid |
|||
} |
|||
|
|||
func (p *UnixProcess) PPid() int { |
|||
return p.ppid |
|||
} |
|||
|
|||
func (p *UnixProcess) Executable() string { |
|||
return p.binary |
|||
} |
|||
|
|||
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() |
|||
} |
@ -0,0 +1,119 @@ |
|||
// +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") |
|||
) |
|||
|
|||
// Some constants from the Windows API
|
|||
const ( |
|||
ERROR_NO_MORE_FILES = 0x12 |
|||
MAX_PATH = 260 |
|||
) |
|||
|
|||
// PROCESSENTRY32 is the Windows API structure that contains a process's
|
|||
// information.
|
|||
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 |
|||
} |
|||
|
|||
func (p *WindowsProcess) Pid() int { |
|||
return p.pid |
|||
} |
|||
|
|||
func (p *WindowsProcess) PPid() int { |
|||
return p.ppid |
|||
} |
|||
|
|||
func (p *WindowsProcess) Executable() string { |
|||
return p.exe |
|||
} |
|||
|
|||
func newWindowsProcess(e *PROCESSENTRY32) *WindowsProcess { |
|||
// Find when the string ends for decoding
|
|||
end := 0 |
|||
for { |
|||
if e.ExeFile[end] == 0 { |
|||
break |
|||
} |
|||
end++ |
|||
} |
|||
|
|||
return &WindowsProcess{ |
|||
pid: int(e.ProcessID), |
|||
ppid: int(e.ParentProcessID), |
|||
exe: syscall.UTF16ToString(e.ExeFile[:end]), |
|||
} |
|||
} |
|||
|
|||
func findProcess(pid int) (Process, error) { |
|||
ps, err := processes() |
|||
if err != nil { |
|||
return nil, 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 |
|||
} |
Carregando…
Criar uma nova questão referindo esta