Files
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

71 lines
1.8 KiB
Go

//go:build darwin
package proc
import (
"os/exec"
"strconv"
"strings"
"github.com/pranshuparmar/witr/pkg/model"
)
// ListLockedFiles uses `lsof -l` to surface file locks. macOS has no
// /proc/locks equivalent; this is best-effort coverage and may take a
// noticeable beat on busy systems because lsof scans every open fd.
func ListLockedFiles() []*model.LockedFile {
// lsof may exit non-zero when it can't read one of the processes it
// scans (permission denied, process exiting mid-scan, etc.) while still
// emitting valid rows on stdout for the rest; salvage stdout when present.
out, err := exec.Command("lsof", "-l", "-n", "-P").Output()
if err != nil && len(out) == 0 {
return nil
}
var locks []*model.LockedFile
for _, line := range strings.Split(string(out), "\n") {
fields := strings.Fields(line)
// COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
if len(fields) < 9 {
continue
}
// lsof prints the lock flag inside the FD column, e.g. "5uW" (W = write lock).
fd := fields[3]
mode := lsofFDLockMode(fd)
if mode == "" {
continue
}
pid, err := strconv.Atoi(fields[1])
if err != nil || pid <= 0 {
continue
}
path := strings.Join(fields[8:], " ")
locks = append(locks, &model.LockedFile{
PID: pid,
Process: fields[0],
Path: path,
Type: "FLOCK",
Mode: mode,
})
}
return locks
}
// lsofFDLockMode extracts the lock indicator from an lsof FD column.
// Per lsof(8): trailing 'W' = write lock, 'R' = read lock, 'r'/'w' = locked
// region, 'u' = upgradable. Returns "" when no lock flag is present.
func lsofFDLockMode(fd string) string {
if fd == "" {
return ""
}
switch fd[len(fd)-1] {
case 'W', 'w':
return "WRITE"
case 'R', 'r':
return "READ"
case 'u', 'U':
return "RW"
}
return ""
}