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