139 lines
2.1 KiB
Go
139 lines
2.1 KiB
Go
|
// +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
|
||
|
}
|