1// +build openbsd 2 3package process 4 5import ( 6 "C" 7 "context" 8 "os/exec" 9 "path/filepath" 10 "strconv" 11 "strings" 12 "unsafe" 13 14 cpu "github.com/shirou/gopsutil/v3/cpu" 15 "github.com/shirou/gopsutil/v3/internal/common" 16 mem "github.com/shirou/gopsutil/v3/mem" 17 net "github.com/shirou/gopsutil/v3/net" 18 "golang.org/x/sys/unix" 19) 20 21func pidsWithContext(ctx context.Context) ([]int32, error) { 22 var ret []int32 23 procs, err := ProcessesWithContext(ctx) 24 if err != nil { 25 return ret, nil 26 } 27 28 for _, p := range procs { 29 ret = append(ret, p.Pid) 30 } 31 32 return ret, nil 33} 34 35func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { 36 k, err := p.getKProc() 37 if err != nil { 38 return 0, err 39 } 40 41 return k.Ppid, nil 42} 43 44func (p *Process) NameWithContext(ctx context.Context) (string, error) { 45 k, err := p.getKProc() 46 if err != nil { 47 return "", err 48 } 49 name := common.IntToString(k.Comm[:]) 50 51 if len(name) >= 15 { 52 cmdlineSlice, err := p.CmdlineSliceWithContext(ctx) 53 if err != nil { 54 return "", err 55 } 56 if len(cmdlineSlice) > 0 { 57 extendedName := filepath.Base(cmdlineSlice[0]) 58 if strings.HasPrefix(extendedName, p.name) { 59 name = extendedName 60 } else { 61 name = cmdlineSlice[0] 62 } 63 } 64 } 65 66 return name, nil 67} 68 69func (p *Process) ExeWithContext(ctx context.Context) (string, error) { 70 return "", common.ErrNotImplementedError 71} 72 73func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { 74 mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv} 75 buf, _, err := common.CallSyscall(mib) 76 77 if err != nil { 78 return nil, err 79 } 80 81 argc := 0 82 argvp := unsafe.Pointer(&buf[0]) 83 argv := *(**C.char)(unsafe.Pointer(argvp)) 84 size := unsafe.Sizeof(argv) 85 var strParts []string 86 87 for argv != nil { 88 strParts = append(strParts, C.GoString(argv)) 89 90 argc++ 91 argv = *(**C.char)(unsafe.Pointer(uintptr(argvp) + uintptr(argc)*size)) 92 } 93 return strParts, nil 94} 95 96func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { 97 argv, err := p.CmdlineSliceWithContext(ctx) 98 if err != nil { 99 return "", err 100 } 101 return strings.Join(argv, " "), nil 102} 103 104func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { 105 return 0, common.ErrNotImplementedError 106} 107 108func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { 109 return nil, common.ErrNotImplementedError 110} 111 112func (p *Process) StatusWithContext(ctx context.Context) ([]string, error) { 113 k, err := p.getKProc() 114 if err != nil { 115 return []string{""}, err 116 } 117 var s string 118 switch k.Stat { 119 case SIDL: 120 case SRUN: 121 case SONPROC: 122 s = Running 123 case SSLEEP: 124 s = Sleep 125 case SSTOP: 126 s = Stop 127 case SDEAD: 128 s = Zombie 129 } 130 131 return []string{s}, nil 132} 133 134func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { 135 // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details 136 pid := p.Pid 137 ps, err := exec.LookPath("ps") 138 if err != nil { 139 return false, err 140 } 141 out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", strconv.Itoa(int(pid))) 142 if err != nil { 143 return false, err 144 } 145 return strings.IndexByte(string(out), '+') != -1, nil 146} 147 148func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { 149 k, err := p.getKProc() 150 if err != nil { 151 return nil, err 152 } 153 154 uids := make([]int32, 0, 3) 155 156 uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid)) 157 158 return uids, nil 159} 160 161func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { 162 k, err := p.getKProc() 163 if err != nil { 164 return nil, err 165 } 166 167 gids := make([]int32, 0, 3) 168 gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid)) 169 170 return gids, nil 171} 172 173func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { 174 k, err := p.getKProc() 175 if err != nil { 176 return nil, err 177 } 178 179 groups := make([]int32, k.Ngroups) 180 for i := int16(0); i < k.Ngroups; i++ { 181 groups[i] = int32(k.Groups[i]) 182 } 183 184 return groups, nil 185} 186 187func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { 188 k, err := p.getKProc() 189 if err != nil { 190 return "", err 191 } 192 193 ttyNr := uint64(k.Tdev) 194 195 termmap, err := getTerminalMap() 196 if err != nil { 197 return "", err 198 } 199 200 return termmap[ttyNr], nil 201} 202 203func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { 204 k, err := p.getKProc() 205 if err != nil { 206 return 0, err 207 } 208 return int32(k.Nice), nil 209} 210 211func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { 212 k, err := p.getKProc() 213 if err != nil { 214 return nil, err 215 } 216 return &IOCountersStat{ 217 ReadCount: uint64(k.Uru_inblock), 218 WriteCount: uint64(k.Uru_oublock), 219 }, nil 220} 221 222func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { 223 /* not supported, just return 1 */ 224 return 1, nil 225} 226 227func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { 228 k, err := p.getKProc() 229 if err != nil { 230 return nil, err 231 } 232 return &cpu.TimesStat{ 233 CPU: "cpu", 234 User: float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000, 235 System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000, 236 }, nil 237} 238 239func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { 240 k, err := p.getKProc() 241 if err != nil { 242 return nil, err 243 } 244 pageSize, err := mem.GetPageSizeWithContext(ctx) 245 if err != nil { 246 return nil, err 247 } 248 249 return &MemoryInfoStat{ 250 RSS: uint64(k.Vm_rssize) * pageSize, 251 VMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) + 252 uint64(k.Vm_ssize), 253 }, nil 254} 255 256func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { 257 pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid) 258 if err != nil { 259 return nil, err 260 } 261 ret := make([]*Process, 0, len(pids)) 262 for _, pid := range pids { 263 np, err := NewProcessWithContext(ctx, pid) 264 if err != nil { 265 return nil, err 266 } 267 ret = append(ret, np) 268 } 269 return ret, nil 270} 271 272func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { 273 return nil, common.ErrNotImplementedError 274} 275 276func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { 277 return nil, common.ErrNotImplementedError 278} 279 280func ProcessesWithContext(ctx context.Context) ([]*Process, error) { 281 results := []*Process{} 282 283 buf, length, err := callKernProcSyscall(KernProcAll, 0) 284 285 if err != nil { 286 return results, err 287 } 288 289 // get kinfo_proc size 290 count := int(length / uint64(sizeOfKinfoProc)) 291 292 // parse buf to procs 293 for i := 0; i < count; i++ { 294 b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc] 295 k, err := parseKinfoProc(b) 296 if err != nil { 297 continue 298 } 299 p, err := NewProcessWithContext(ctx, int32(k.Pid)) 300 if err != nil { 301 continue 302 } 303 304 results = append(results, p) 305 } 306 307 return results, nil 308} 309 310func (p *Process) getKProc() (*KinfoProc, error) { 311 buf, length, err := callKernProcSyscall(KernProcPID, p.Pid) 312 if err != nil { 313 return nil, err 314 } 315 if length != sizeOfKinfoProc { 316 return nil, err 317 } 318 319 k, err := parseKinfoProc(buf) 320 if err != nil { 321 return nil, err 322 } 323 return &k, nil 324} 325 326func callKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) { 327 mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0} 328 mibptr := unsafe.Pointer(&mib[0]) 329 miblen := uint64(len(mib)) 330 length := uint64(0) 331 _, _, err := unix.Syscall6( 332 unix.SYS___SYSCTL, 333 uintptr(mibptr), 334 uintptr(miblen), 335 0, 336 uintptr(unsafe.Pointer(&length)), 337 0, 338 0) 339 if err != 0 { 340 return nil, length, err 341 } 342 343 count := int32(length / uint64(sizeOfKinfoProc)) 344 mib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count} 345 mibptr = unsafe.Pointer(&mib[0]) 346 miblen = uint64(len(mib)) 347 // get proc info itself 348 buf := make([]byte, length) 349 _, _, err = unix.Syscall6( 350 unix.SYS___SYSCTL, 351 uintptr(mibptr), 352 uintptr(miblen), 353 uintptr(unsafe.Pointer(&buf[0])), 354 uintptr(unsafe.Pointer(&length)), 355 0, 356 0) 357 if err != 0 { 358 return buf, length, err 359 } 360 361 return buf, length, nil 362} 363