1// +build openbsd 2 3package process 4 5import ( 6 "C" 7 "bytes" 8 "context" 9 "encoding/binary" 10 "os/exec" 11 "strconv" 12 "strings" 13 "unsafe" 14 15 cpu "github.com/shirou/gopsutil/cpu" 16 "github.com/shirou/gopsutil/internal/common" 17 mem "github.com/shirou/gopsutil/mem" 18 net "github.com/shirou/gopsutil/net" 19 "golang.org/x/sys/unix" 20) 21 22// MemoryInfoExStat is different between OSes 23type MemoryInfoExStat struct { 24} 25 26type MemoryMapsStat struct { 27} 28 29func pidsWithContext(ctx context.Context) ([]int32, error) { 30 var ret []int32 31 procs, err := Processes() 32 if err != nil { 33 return ret, nil 34 } 35 36 for _, p := range procs { 37 ret = append(ret, p.Pid) 38 } 39 40 return ret, nil 41} 42 43func (p *Process) Ppid() (int32, error) { 44 return p.PpidWithContext(context.Background()) 45} 46 47func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { 48 k, err := p.getKProc() 49 if err != nil { 50 return 0, err 51 } 52 53 return k.Ppid, nil 54} 55func (p *Process) Name() (string, error) { 56 return p.NameWithContext(context.Background()) 57} 58 59func (p *Process) NameWithContext(ctx context.Context) (string, error) { 60 k, err := p.getKProc() 61 if err != nil { 62 return "", err 63 } 64 65 return common.IntToString(k.Comm[:]), nil 66} 67func (p *Process) Tgid() (int32, error) { 68 return 0, common.ErrNotImplementedError 69} 70func (p *Process) Exe() (string, error) { 71 return p.ExeWithContext(context.Background()) 72} 73 74func (p *Process) ExeWithContext(ctx context.Context) (string, error) { 75 return "", common.ErrNotImplementedError 76} 77 78func (p *Process) CmdlineSlice() ([]string, error) { 79 return p.CmdlineSliceWithContext(context.Background()) 80} 81 82func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { 83 mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv} 84 buf, _, err := common.CallSyscall(mib) 85 86 if err != nil { 87 return nil, err 88 } 89 90 argc := 0 91 argvp := unsafe.Pointer(&buf[0]) 92 argv := *(**C.char)(unsafe.Pointer(argvp)) 93 size := unsafe.Sizeof(argv) 94 var strParts []string 95 96 for argv != nil { 97 strParts = append(strParts, C.GoString(argv)) 98 99 argc++ 100 argv = *(**C.char)(unsafe.Pointer(uintptr(argvp) + uintptr(argc)*size)) 101 } 102 return strParts, nil 103} 104 105func (p *Process) Cmdline() (string, error) { 106 return p.CmdlineWithContext(context.Background()) 107} 108 109func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { 110 argv, err := p.CmdlineSlice() 111 if err != nil { 112 return "", err 113 } 114 return strings.Join(argv, " "), nil 115} 116 117func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { 118 return 0, common.ErrNotImplementedError 119} 120func (p *Process) Cwd() (string, error) { 121 return p.CwdWithContext(context.Background()) 122} 123 124func (p *Process) CwdWithContext(ctx context.Context) (string, error) { 125 return "", common.ErrNotImplementedError 126} 127func (p *Process) Parent() (*Process, error) { 128 return p.ParentWithContext(context.Background()) 129} 130 131func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { 132 return p, common.ErrNotImplementedError 133} 134func (p *Process) Status() (string, error) { 135 return p.StatusWithContext(context.Background()) 136} 137 138func (p *Process) StatusWithContext(ctx context.Context) (string, error) { 139 k, err := p.getKProc() 140 if err != nil { 141 return "", err 142 } 143 var s string 144 switch k.Stat { 145 case SIDL: 146 case SRUN: 147 case SONPROC: 148 s = "R" 149 case SSLEEP: 150 s = "S" 151 case SSTOP: 152 s = "T" 153 case SDEAD: 154 s = "Z" 155 } 156 157 return s, nil 158} 159func (p *Process) Foreground() (bool, error) { 160 return p.ForegroundWithContext(context.Background()) 161} 162 163func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { 164 // see https://github.com/shirou/gopsutil/issues/596#issuecomment-432707831 for implementation details 165 pid := p.Pid 166 ps, err := exec.LookPath("ps") 167 if err != nil { 168 return false, err 169 } 170 out, err := invoke.CommandWithContext(ctx, ps, "-o", "stat=", "-p", strconv.Itoa(int(pid))) 171 if err != nil { 172 return false, err 173 } 174 return strings.IndexByte(string(out), '+') != -1, nil 175} 176func (p *Process) Uids() ([]int32, error) { 177 return p.UidsWithContext(context.Background()) 178} 179 180func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { 181 k, err := p.getKProc() 182 if err != nil { 183 return nil, err 184 } 185 186 uids := make([]int32, 0, 3) 187 188 uids = append(uids, int32(k.Ruid), int32(k.Uid), int32(k.Svuid)) 189 190 return uids, nil 191} 192func (p *Process) Gids() ([]int32, error) { 193 return p.GidsWithContext(context.Background()) 194} 195 196func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { 197 k, err := p.getKProc() 198 if err != nil { 199 return nil, err 200 } 201 202 gids := make([]int32, 0, 3) 203 gids = append(gids, int32(k.Rgid), int32(k.Ngroups), int32(k.Svgid)) 204 205 return gids, nil 206} 207func (p *Process) Terminal() (string, error) { 208 return p.TerminalWithContext(context.Background()) 209} 210 211func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { 212 k, err := p.getKProc() 213 if err != nil { 214 return "", err 215 } 216 217 ttyNr := uint64(k.Tdev) 218 219 termmap, err := getTerminalMap() 220 if err != nil { 221 return "", err 222 } 223 224 return termmap[ttyNr], nil 225} 226func (p *Process) Nice() (int32, error) { 227 return p.NiceWithContext(context.Background()) 228} 229 230func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { 231 k, err := p.getKProc() 232 if err != nil { 233 return 0, err 234 } 235 return int32(k.Nice), nil 236} 237func (p *Process) IOnice() (int32, error) { 238 return p.IOniceWithContext(context.Background()) 239} 240 241func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { 242 return 0, common.ErrNotImplementedError 243} 244func (p *Process) Rlimit() ([]RlimitStat, error) { 245 return p.RlimitWithContext(context.Background()) 246} 247 248func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { 249 var rlimit []RlimitStat 250 return rlimit, common.ErrNotImplementedError 251} 252func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) { 253 return p.RlimitUsageWithContext(context.Background(), gatherUsed) 254} 255 256func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { 257 var rlimit []RlimitStat 258 return rlimit, common.ErrNotImplementedError 259} 260func (p *Process) IOCounters() (*IOCountersStat, error) { 261 return p.IOCountersWithContext(context.Background()) 262} 263 264func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { 265 k, err := p.getKProc() 266 if err != nil { 267 return nil, err 268 } 269 return &IOCountersStat{ 270 ReadCount: uint64(k.Uru_inblock), 271 WriteCount: uint64(k.Uru_oublock), 272 }, nil 273} 274func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { 275 return p.NumCtxSwitchesWithContext(context.Background()) 276} 277 278func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { 279 return nil, common.ErrNotImplementedError 280} 281func (p *Process) NumFDs() (int32, error) { 282 return p.NumFDsWithContext(context.Background()) 283} 284 285func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { 286 return 0, common.ErrNotImplementedError 287} 288func (p *Process) NumThreads() (int32, error) { 289 return p.NumThreadsWithContext(context.Background()) 290} 291 292func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { 293 /* not supported, just return 1 */ 294 return 1, nil 295} 296func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) { 297 return p.ThreadsWithContext(context.Background()) 298} 299 300func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { 301 ret := make(map[int32]*cpu.TimesStat) 302 return ret, common.ErrNotImplementedError 303} 304func (p *Process) Times() (*cpu.TimesStat, error) { 305 return p.TimesWithContext(context.Background()) 306} 307 308func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { 309 k, err := p.getKProc() 310 if err != nil { 311 return nil, err 312 } 313 return &cpu.TimesStat{ 314 CPU: "cpu", 315 User: float64(k.Uutime_sec) + float64(k.Uutime_usec)/1000000, 316 System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000, 317 }, nil 318} 319func (p *Process) CPUAffinity() ([]int32, error) { 320 return p.CPUAffinityWithContext(context.Background()) 321} 322 323func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { 324 return nil, common.ErrNotImplementedError 325} 326func (p *Process) MemoryInfo() (*MemoryInfoStat, error) { 327 return p.MemoryInfoWithContext(context.Background()) 328} 329 330func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { 331 k, err := p.getKProc() 332 if err != nil { 333 return nil, err 334 } 335 pageSize, err := mem.GetPageSize() 336 if err != nil { 337 return nil, err 338 } 339 340 return &MemoryInfoStat{ 341 RSS: uint64(k.Vm_rssize) * pageSize, 342 VMS: uint64(k.Vm_tsize) + uint64(k.Vm_dsize) + 343 uint64(k.Vm_ssize), 344 }, nil 345} 346func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { 347 return p.MemoryInfoExWithContext(context.Background()) 348} 349 350func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { 351 return nil, common.ErrNotImplementedError 352} 353 354func (p *Process) PageFaults() (*PageFaultsStat, error) { 355 return p.PageFaultsWithContext(context.Background()) 356} 357 358func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { 359 return nil, common.ErrNotImplementedError 360} 361 362func (p *Process) Children() ([]*Process, error) { 363 return p.ChildrenWithContext(context.Background()) 364} 365 366func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { 367 pids, err := common.CallPgrepWithContext(ctx, invoke, p.Pid) 368 if err != nil { 369 return nil, err 370 } 371 ret := make([]*Process, 0, len(pids)) 372 for _, pid := range pids { 373 np, err := NewProcess(pid) 374 if err != nil { 375 return nil, err 376 } 377 ret = append(ret, np) 378 } 379 return ret, nil 380} 381 382func (p *Process) OpenFiles() ([]OpenFilesStat, error) { 383 return p.OpenFilesWithContext(context.Background()) 384} 385 386func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) { 387 return nil, common.ErrNotImplementedError 388} 389 390func (p *Process) Connections() ([]net.ConnectionStat, error) { 391 return p.ConnectionsWithContext(context.Background()) 392} 393 394func (p *Process) ConnectionsWithContext(ctx context.Context) ([]net.ConnectionStat, error) { 395 return nil, common.ErrNotImplementedError 396} 397 398func (p *Process) ConnectionsMax(max int) ([]net.ConnectionStat, error) { 399 return p.ConnectionsMaxWithContext(context.Background(), max) 400} 401 402func (p *Process) ConnectionsMaxWithContext(ctx context.Context, max int) ([]net.ConnectionStat, error) { 403 return []net.ConnectionStat{}, common.ErrNotImplementedError 404} 405 406func (p *Process) NetIOCounters(pernic bool) ([]net.IOCountersStat, error) { 407 return p.NetIOCountersWithContext(context.Background(), pernic) 408} 409 410func (p *Process) NetIOCountersWithContext(ctx context.Context, pernic bool) ([]net.IOCountersStat, error) { 411 return nil, common.ErrNotImplementedError 412} 413 414func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) { 415 return p.MemoryMapsWithContext(context.Background(), grouped) 416} 417 418func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { 419 var ret []MemoryMapsStat 420 return &ret, common.ErrNotImplementedError 421} 422 423func Processes() ([]*Process, error) { 424 return ProcessesWithContext(context.Background()) 425} 426 427func ProcessesWithContext(ctx context.Context) ([]*Process, error) { 428 results := []*Process{} 429 430 buf, length, err := CallKernProcSyscall(KernProcAll, 0) 431 432 if err != nil { 433 return results, err 434 } 435 436 // get kinfo_proc size 437 count := int(length / uint64(sizeOfKinfoProc)) 438 439 // parse buf to procs 440 for i := 0; i < count; i++ { 441 b := buf[i*sizeOfKinfoProc : (i+1)*sizeOfKinfoProc] 442 k, err := parseKinfoProc(b) 443 if err != nil { 444 continue 445 } 446 p, err := NewProcess(int32(k.Pid)) 447 if err != nil { 448 continue 449 } 450 451 results = append(results, p) 452 } 453 454 return results, nil 455} 456 457func parseKinfoProc(buf []byte) (KinfoProc, error) { 458 var k KinfoProc 459 br := bytes.NewReader(buf) 460 err := common.Read(br, binary.LittleEndian, &k) 461 return k, err 462} 463 464func (p *Process) getKProc() (*KinfoProc, error) { 465 return p.getKProcWithContext(context.Background()) 466} 467 468func (p *Process) getKProcWithContext(ctx context.Context) (*KinfoProc, error) { 469 buf, length, err := CallKernProcSyscall(KernProcPID, p.Pid) 470 if err != nil { 471 return nil, err 472 } 473 if length != sizeOfKinfoProc { 474 return nil, err 475 } 476 477 k, err := parseKinfoProc(buf) 478 if err != nil { 479 return nil, err 480 } 481 return &k, nil 482} 483 484func CallKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) { 485 return CallKernProcSyscallWithContext(context.Background(), op, arg) 486} 487 488func CallKernProcSyscallWithContext(ctx context.Context, op int32, arg int32) ([]byte, uint64, error) { 489 mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0} 490 mibptr := unsafe.Pointer(&mib[0]) 491 miblen := uint64(len(mib)) 492 length := uint64(0) 493 _, _, err := unix.Syscall6( 494 unix.SYS___SYSCTL, 495 uintptr(mibptr), 496 uintptr(miblen), 497 0, 498 uintptr(unsafe.Pointer(&length)), 499 0, 500 0) 501 if err != 0 { 502 return nil, length, err 503 } 504 505 count := int32(length / uint64(sizeOfKinfoProc)) 506 mib = []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, count} 507 mibptr = unsafe.Pointer(&mib[0]) 508 miblen = uint64(len(mib)) 509 // get proc info itself 510 buf := make([]byte, length) 511 _, _, err = unix.Syscall6( 512 unix.SYS___SYSCTL, 513 uintptr(mibptr), 514 uintptr(miblen), 515 uintptr(unsafe.Pointer(&buf[0])), 516 uintptr(unsafe.Pointer(&length)), 517 0, 518 0) 519 if err != 0 { 520 return buf, length, err 521 } 522 523 return buf, length, nil 524} 525