1// +build dragonfly 2 3package ps 4 5import ( 6 "bytes" 7 "encoding/binary" 8 "fmt" 9 "syscall" 10 "unsafe" 11) 12 13// copied from sys/sysctl.h 14const ( 15 CTL_KERN = 1 // "high kernel": proc, limits 16 KERN_PROC = 14 // struct: process entries 17 KERN_PROC_PID = 1 // by process id 18 KERN_PROC_PROC = 8 // only return procs 19 KERN_PROC_PATHNAME = 12 // path to executable 20) 21 22// copied from sys/user.h 23type Kinfo_proc struct { 24 Ki_structsize int32 25 Ki_layout int32 26 Ki_args int64 27 Ki_paddr int64 28 Ki_addr int64 29 Ki_tracep int64 30 Ki_textvp int64 31 Ki_fd int64 32 Ki_vmspace int64 33 Ki_wchan int64 34 Ki_pid int32 35 Ki_ppid int32 36 Ki_pgid int32 37 Ki_tpgid int32 38 Ki_sid int32 39 Ki_tsid int32 40 Ki_jobc [2]byte 41 Ki_spare_short1 [2]byte 42 Ki_tdev int32 43 Ki_siglist [16]byte 44 Ki_sigmask [16]byte 45 Ki_sigignore [16]byte 46 Ki_sigcatch [16]byte 47 Ki_uid int32 48 Ki_ruid int32 49 Ki_svuid int32 50 Ki_rgid int32 51 Ki_svgid int32 52 Ki_ngroups [2]byte 53 Ki_spare_short2 [2]byte 54 Ki_groups [64]byte 55 Ki_size int64 56 Ki_rssize int64 57 Ki_swrss int64 58 Ki_tsize int64 59 Ki_dsize int64 60 Ki_ssize int64 61 Ki_xstat [2]byte 62 Ki_acflag [2]byte 63 Ki_pctcpu int32 64 Ki_estcpu int32 65 Ki_slptime int32 66 Ki_swtime int32 67 Ki_cow int32 68 Ki_runtime int64 69 Ki_start [16]byte 70 Ki_childtime [16]byte 71 Ki_flag int64 72 Ki_kiflag int64 73 Ki_traceflag int32 74 Ki_stat [1]byte 75 Ki_nice [1]byte 76 Ki_lock [1]byte 77 Ki_rqindex [1]byte 78 Ki_oncpu [1]byte 79 Ki_lastcpu [1]byte 80 Ki_ocomm [17]byte 81 Ki_wmesg [9]byte 82 Ki_login [18]byte 83 Ki_lockname [9]byte 84 Ki_comm [20]byte 85 Ki_emul [17]byte 86 Ki_sparestrings [68]byte 87 Ki_spareints [36]byte 88 Ki_cr_flags int32 89 Ki_jid int32 90 Ki_numthreads int32 91 Ki_tid int32 92 Ki_pri int32 93 Ki_rusage [144]byte 94 Ki_rusage_ch [144]byte 95 Ki_pcb int64 96 Ki_kstack int64 97 Ki_udata int64 98 Ki_tdaddr int64 99 Ki_spareptrs [48]byte 100 Ki_spareint64s [96]byte 101 Ki_sflag int64 102 Ki_tdflags int64 103} 104 105// UnixProcess is an implementation of Process that contains Unix-specific 106// fields and information. 107type UnixProcess struct { 108 pid int 109 ppid int 110 state rune 111 pgrp int 112 sid int 113 114 binary string 115} 116 117// Pid returns process id 118func (p *UnixProcess) Pid() int { 119 return p.pid 120} 121 122// PPid returns parent process id 123func (p *UnixProcess) PPid() int { 124 return p.ppid 125} 126 127// Executable returns process executable name 128func (p *UnixProcess) Executable() string { 129 return p.binary 130} 131 132// Path returns path to process executable 133func (p *UnixProcess) Path() (string, error) { 134 return "", fmt.Errorf("Unsupported") 135} 136 137// Refresh reloads all the data associated with this process. 138func (p *UnixProcess) Refresh() error { 139 140 mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PID, int32(p.pid)} 141 142 buf, length, err := call_syscall(mib) 143 if err != nil { 144 return err 145 } 146 proc_k := Kinfo_proc{} 147 if length != uint64(unsafe.Sizeof(proc_k)) { 148 return err 149 } 150 151 k, err := parse_kinfo_proc(buf) 152 if err != nil { 153 return err 154 } 155 156 p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k) 157 return nil 158} 159 160func copy_params(k *Kinfo_proc) (int, int, int, string) { 161 n := -1 162 for i, b := range k.Ki_comm { 163 if b == 0 { 164 break 165 } 166 n = i + 1 167 } 168 comm := string(k.Ki_comm[:n]) 169 170 return int(k.Ki_ppid), int(k.Ki_pgid), int(k.Ki_sid), comm 171} 172 173func findProcess(pid int) (Process, error) { 174 mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, int32(pid)} 175 176 _, _, err := call_syscall(mib) 177 if err != nil { 178 return nil, err 179 } 180 181 return newUnixProcess(pid) 182} 183 184func processes() ([]Process, error) { 185 results := make([]Process, 0, 50) 186 187 mib := []int32{CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0} 188 buf, length, err := call_syscall(mib) 189 if err != nil { 190 return results, err 191 } 192 193 // get kinfo_proc size 194 k := Kinfo_proc{} 195 procinfo_len := int(unsafe.Sizeof(k)) 196 count := int(length / uint64(procinfo_len)) 197 198 // parse buf to procs 199 for i := 0; i < count; i++ { 200 b := buf[i*procinfo_len : i*procinfo_len+procinfo_len] 201 k, err := parse_kinfo_proc(b) 202 if err != nil { 203 continue 204 } 205 p, err := newUnixProcess(int(k.Ki_pid)) 206 if err != nil { 207 continue 208 } 209 p.ppid, p.pgrp, p.sid, p.binary = copy_params(&k) 210 211 results = append(results, p) 212 } 213 214 return results, nil 215} 216 217func parse_kinfo_proc(buf []byte) (Kinfo_proc, error) { 218 var k Kinfo_proc 219 br := bytes.NewReader(buf) 220 err := binary.Read(br, binary.LittleEndian, &k) 221 if err != nil { 222 return k, err 223 } 224 225 return k, nil 226} 227 228func call_syscall(mib []int32) ([]byte, uint64, error) { 229 miblen := uint64(len(mib)) 230 231 // get required buffer size 232 length := uint64(0) 233 _, _, err := syscall.RawSyscall6( 234 syscall.SYS___SYSCTL, 235 uintptr(unsafe.Pointer(&mib[0])), 236 uintptr(miblen), 237 0, 238 uintptr(unsafe.Pointer(&length)), 239 0, 240 0) 241 if err != 0 { 242 b := make([]byte, 0) 243 return b, length, err 244 } 245 if length == 0 { 246 b := make([]byte, 0) 247 return b, length, err 248 } 249 // get proc info itself 250 buf := make([]byte, length) 251 _, _, err = syscall.RawSyscall6( 252 syscall.SYS___SYSCTL, 253 uintptr(unsafe.Pointer(&mib[0])), 254 uintptr(miblen), 255 uintptr(unsafe.Pointer(&buf[0])), 256 uintptr(unsafe.Pointer(&length)), 257 0, 258 0) 259 if err != 0 { 260 return buf, length, err 261 } 262 263 return buf, length, nil 264} 265 266func newUnixProcess(pid int) (*UnixProcess, error) { 267 p := &UnixProcess{pid: pid} 268 return p, p.Refresh() 269} 270