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()
 | 
						|
}
 |