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