# How witr Detects File Locks on Linux, macOS, and FreeBSD

> Learn how witr detects file locks on Linux, macOS, and FreeBSD using platform-specific system calls and kernel interfaces. Understand the underlying mechanisms for effective file lock management.

- Repository: [Pranshu Parmar/witr](https://github.com/pranshuparmar/witr)
- Tags: internals
- Published: 2026-08-09

---

**witr detects file locks by using platform-specific system calls and kernel interfaces—reading `/proc/locks` on Linux, executing `lsof` on macOS, and calling `fstat` on FreeBSD—to map abstract lock metadata to concrete file paths.**

The **witr** repository implements portable file lock detection across Unix variants through its `internal/proc` package. Each operating system exposes lock state differently, requiring distinct kernel-interaction strategies that converge on a unified Go API for the application layer.

## Linux File Lock Detection via /proc/locks

On Linux, witr discovers active locks by parsing the kernel-exposed `/proc/locks` virtual file. This file contains system-wide lock records with device and inode identifiers that must be translated into human-readable paths.

### Parsing Kernel Lock Entries

The `ListLockedFiles` function in [`internal/proc/locks_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/locks_linux.go) opens `/proc/locks` and parses each line into structured data. Each entry specifies the locking process ID, lock type (POSIX or BSD), and the target file’s device:inode pair.

### Resolving Paths via /proc/[pid]/fd

Since `/proc/locks` only provides device and inode numbers, the `resolveLockPath` helper traverses `/proc/<pid>/fd` directories for the locking process. By comparing the device:inode of each file descriptor against the lock entry, witr resolves the abstract identifier to an absolute path that the UI can display.

## macOS File Lock Detection Using lsof

macOS (Darwin) lacks a `/proc` filesystem equivalent for lock inspection, so witr shells out to the `lsof` utility to query the kernel’s open-file table.

### Executing lsof -l in locks_darwin.go

The `ListLockedFiles` function in [`internal/proc/locks_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/locks_darwin.go) executes `lsof -l`, which lists open files with lock indicators in the "FD" column. This approach avoids the need for kernel extensions or private system calls while providing visibility into advisory locks.

### Parsing Lock Modes with lsofFDLockMode

The `lsofFDLockMode` helper extracts the lock state from the FD column, where **"r"** indicates a read lock and **"w"** indicates a write lock. The parser converts these markers into standardized `model.LockedFile` entries with normalized lock modes.

## FreeBSD File Lock Detection via fstat

On FreeBSD, witr uses the `fstat` system call to query lock information directly from the kernel without parsing text files or executing external commands.

### Querying Kernel State in locks_freebsd.go

The `ListLockedFiles` function in [`internal/proc/locks_freebsd.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/locks_freebsd.go) invokes `fstat` to retrieve `struct Stat_t` entries for open files. It examines specific lock flags within these structures to identify which files are currently locked and maps them to the corresponding process IDs.

## Unified Interface and Usage Examples

All three implementations return a slice of `*model.LockedFile`, allowing the rest of the application to call `proc.ListLockedFiles()` without platform-specific conditionals. The following examples demonstrate how to consume this API:

```go
// Retrieve all file locks visible on the current system.
locked := proc.ListLockedFiles()
for _, l := range locked {
    fmt.Printf("PID %d holds a %s lock on %s\n",
        l.Pid, l.LockMode, l.Path)
}

```

```go
// Example of filtering only write locks.
var writeLocks []*model.LockedFile
for _, l := range proc.ListLockedFiles() {
    if l.LockMode == "WRITE" {
        writeLocks = append(writeLocks, l)
    }
}

```

## Summary

- **Linux**: Parses `/proc/locks` and resolves device:inode pairs to paths via `/proc/<pid>/fd` lookups in [`internal/proc/locks_linux.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/locks_linux.go).
- **macOS**: Executes `lsof -l` and parses the FD column for lock indicators in [`internal/proc/locks_darwin.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/locks_darwin.go).
- **FreeBSD**: Uses the `fstat` syscall to inspect `struct Stat_t` lock flags directly in [`internal/proc/locks_freebsd.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/locks_freebsd.go).
- All platforms return `[]*model.LockedFile` through the common `ListLockedFiles()` API.

## Frequently Asked Questions

### How does witr detect file locks on Linux without root privileges?

witr reads the world-readable `/proc/locks` file and traverses `/proc/<pid>/fd` directories, which are accessible to the process owner. This allows lock detection without elevated permissions for the user's own processes, though other users' file descriptor directories remain inaccessible.

### Why does the macOS implementation use lsof instead of a syscall?

macOS does not expose a stable kernel interface for querying file locks directly from user space like Linux's `/proc` filesystem. The `lsof` command provides the most reliable method to inspect lock states without requiring kernel extensions or private APIs that could break between OS versions.

### What lock types can witr identify on FreeBSD?

The FreeBSD implementation examines lock flags in the `struct Stat_t` returned by `fstat`, enabling detection of advisory and mandatory locks held by processes. The specific lock mode interpretation depends on the flag analysis performed in [`internal/proc/locks_freebsd.go`](https://github.com/pranshuparmar/witr/blob/main/internal/proc/locks_freebsd.go).

### Can witr detect file locks held by other users?

On Linux, witr can see system-wide lock metadata in `/proc/locks` but can only resolve paths for processes owned by the current user due to `/proc/<pid>/fd` permission restrictions. macOS and FreeBSD visibility depends on process permissions and whether the user has privileges to inspect other processes' file descriptors.