435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
261 lines
5.3 KiB
Go
261 lines
5.3 KiB
Go
// +build freebsd
|
|
|
|
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()
|
|
}
|