forked from mitchellh/go-ps
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for OpenBSD (mitchellh#7)
- Loading branch information
Showing
2 changed files
with
330 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,302 @@ | ||
// +build openbsd,amd64 | ||
|
||
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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// +build openbsd | ||
|
||
package ps | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestFindProcessOpenBSD(t *testing.T) { | ||
proc := testFindProcess(t, "go-ps.test") | ||
assert.True(t, proc.PPid() > 0) | ||
} | ||
|
||
func TestProcessesOpenBSD(t *testing.T) { | ||
testProcesses(t, "go") | ||
} | ||
|
||
/* | ||
// Currently querying for -1 will return -1 :P | ||
func TestProcessesOpenBSDError(t *testing.T) { | ||
proc, err := findProcess(-1) | ||
assert.Nil(t, proc) | ||
assert.Nil(t, err) | ||
} | ||
*/ |