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