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