项目文件夹

文件
wehub-resource-sync 36b3af2e3d
PR Check / Code Quality: Format (push) Failing after 1s
PR Check / Code Quality: Lint (darwin) (push) Failing after 0s
PR Check / Code Quality: Lint (freebsd) (push) Failing after 1s
PR Check / Code Quality: Lint (windows) (push) Failing after 1s
PR Check / Code Quality: Lint (linux) (push) Failing after 1s
PR Check / Security: Vulnerability Scan (push) Failing after 0s
Update Documentation / update-docs (push) Failing after 2s
PR Check / Code Quality: Vendor (push) Failing after 1s
PR Check / Code Quality: Coverage (push) Failing after 0s
PR Check / Tests: Unit (macos-latest) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04) (push) Has been cancelled
PR Check / Tests: Unit (ubuntu-24.04-arm) (push) Has been cancelled
PR Check / Tests: Unit (windows-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:22:06 +08:00

119 行
2.6 KiB
Go

//go:build freebsd
package proc
import (
"os/exec"
"slices"
"strconv"
"strings"
"github.com/pranshuparmar/witr/pkg/model"
)
// GetFileContext returns file descriptor and lock info for a process
func GetFileContext(pid int) *model.FileContext {
ctx := &model.FileContext{}
// Run fstat once and reuse output for both open file count and lock detection
fstatOutput, _ := exec.Command("fstat", "-p", strconv.Itoa(pid)).Output()
openFiles, fileLimit := getOpenFileCount(fstatOutput, pid)
ctx.OpenFiles = openFiles
ctx.FileLimit = fileLimit
ctx.LockedFiles = getLockedFiles(fstatOutput)
// Only return if we have meaningful data to show
// Show if: high file usage (>50% of limit) or has locks
if len(ctx.LockedFiles) > 0 {
return ctx
}
if ctx.FileLimit > 0 && ctx.OpenFiles > 0 {
usagePercent := float64(ctx.OpenFiles) / float64(ctx.FileLimit) * 100
if usagePercent > 50 {
return ctx
}
}
return nil
}
func getOpenFileCount(fstatOut []byte, pid int) (int, int) {
if len(fstatOut) == 0 {
return 0, 0
}
openFiles := 0
for line := range strings.Lines(string(fstatOut)) {
if strings.TrimSpace(line) != "" {
openFiles++
}
}
if openFiles > 0 {
openFiles-- // Subtract header line
}
// Get file limit using sysctl or limits
fileLimit := getFileLimit(pid)
return openFiles, fileLimit
}
// getFileLimit returns the file descriptor limit for a process
func getFileLimit(pid int) int {
// Try procstat to get limits
out, err := exec.Command("procstat", "-l", strconv.Itoa(pid)).Output()
if err == nil {
// Parse procstat -l output for openfiles limit
for line := range strings.Lines(string(out)) {
if strings.Contains(line, "openfiles") {
fields := strings.Fields(line)
if len(fields) >= 3 {
limit, err := strconv.Atoi(fields[2])
if err == nil {
return limit
}
}
}
}
}
// Fallback: get system-wide limit
out, err = exec.Command("sysctl", "-n", "kern.maxfilesperproc").Output()
if err == nil {
limit, err := strconv.Atoi(strings.TrimSpace(string(out)))
if err == nil {
return limit
}
}
// Default FreeBSD limit
return 1024
}
func getLockedFiles(fstatOut []byte) []string {
var locked []string
if len(fstatOut) == 0 {
return locked
}
for line := range strings.Lines(string(fstatOut)) {
// Look for lock indicators in the output
if strings.Contains(line, ".lock") ||
strings.Contains(line, ".pid") ||
strings.Contains(line, "/lock") {
fields := strings.Fields(line)
if len(fields) >= 8 {
fileName := fields[len(fields)-1]
if !slices.Contains(locked, fileName) {
locked = append(locked, fileName)
}
}
}
}
return locked
}