or symlink into your fpath

September 5, 2026 · View on GitHub

 ██▓      ██████  ▒█████    █████▒██████  ██████
▓██▒    ▒██    ▒ ▒██▒  ██▒▓██   ▒██   ▒ ▒██    ▒
▒██░    ░ ▓██▄   ▒██░  ██▒▒████ ░▓██▄    ░ ▓██▄
▒██░      ▒   ██▒▒██   ██░░▓█▒  ░▒   ██▒  ▒   ██▒
░██████▒▒██████▒▒░ ████▓▒░░▒█░  ▒██████▒▒██████▒▒
░ ▒░▓  ░▒ ▒▓▒ ▒ ░░ ▒░▒░▒░  ▒ ░ ▒ ▒▓▒ ▒ ░ ▒▓▒ ▒ ░
░ ░ ▒  ░░ ░▒  ░ ░  ░ ▒ ▒░  ░   ░ ░▒  ░ ░ ░▒  ░ ░
  ░ ░  ░ ░  ░    ░ ░ ░ ▒   ░ ░ ░ ░  ░   ░ ░  ░
    ░        ░        ░ ░           ░           ░

CI Crates.io Downloads Docs.rs Docs License: MIT

[LIST SYSTEM OPEN FILES // RUST CORE // 5-21× FASTER THAN lsof]

"Rewritten in Rust. Faster. Safer. The same cyberpunk soul."

lsofrsList System Open Files in Rust. A Rust rewrite of lsofng, the modernized lsof diagnostic tool. Maps the invisible topology between processes and the files they hold open: regular files, directories, sockets, pipes, devices, kqueues — anything the kernel touches. If a process has a file descriptor, lsofrs sees it. lsf is the shorter form of lsofrs (same binary; quicker to type).

Read the Docs · Engineering Report · lsofng · strykelang · zshrs


Table of Contents


[0x00] WHAT IS THIS

lsofrs --help


[0x01] JACK IN — INSTALL

Fastest path — Homebrew tap (auto-bumped by each release):

brew tap MenkeTechnologies/menketech    # one-time
brew install lsofrs

Or build from source:

cargo build --release
sudo cp target/release/lsf /usr/local/sbin/

The same build also emits target/release/lsf (shorter form of lsofrs; same binary). Copy that too if you want both on PATH.

Or install directly:

cargo install lsofrs                    # installs `lsofrs` and `lsf`
cargo install lsof                      # installs the `lsof` command name itself
cargo install --path .                  # from a checkout

The lsof crate is a single fn main() over lsofrs::run() — same binary behaviour under the traditional name, and it shadows the system lsof on PATH.

Install the man pages (short + full reference):

sudo cp man/man1/lsofrs.1    /usr/local/share/man/man1/
sudo cp man/man1/lsofrsall.1 /usr/local/share/man/man1/
man lsofrs        # short reference
man lsofrsall     # full reference (all flags, modes, themes, architecture)

[0x02] USAGE

lsf                           # list all open files
lsf -p 1234                   # files for PID 1234
lsf -c Chrome                 # files for Chrome processes
lsf -u root                   # files for root user
lsf -i                        # network connections only
lsf -i :8080                  # who's listening on port 8080
lsf /path/to/file             # who has this file open
lsf -t -c nginx               # just PIDs (for scripting)

Network Filters

lsf -i                        # all network files
lsf -i 4                      # IPv4 only
lsf -i 6                      # IPv6 only
lsf -i TCP                    # TCP only
lsf -i :443                   # port 443
lsf -i TCP:443                # TCP port 443
lsf -i -n                     # skip reverse DNS (addresses stay numeric)
lsf -i -P                     # skip /etc/services (ports stay numeric)

Host names and service names are resolved by default, as lsof does; -n and -P turn off the respective lookup. Reverse DNS dominates the runtime of a listing that contains unresolvable remote addresses, so -n is worth having in scripts.

Output Formats

lsf                           # columnar (default, cyberpunk-themed on TTY)
lsf --json                    # JSON array output
lsf -J                        # JSON (short form)
lsf -F pcfn                   # field output (p=pid, c=cmd, f=fd, n=name)
lsf -F                        # field output, every field
lsf -F ?                      # list the field identifiers
lsf -t                        # terse (PIDs only)
lsf +L                        # add NLINK (link count) column
lsf +L1                       # select unlinked open files (link count < 1)

Selection Combinators

lsf -p 1234,5678              # multiple PIDs
lsf -u root,wizard            # multiple users
lsf -p ^1234                  # exclude PID 1234
lsf -u ^root                  # exclude root
lsf -a -p 1234 -i             # AND: PID 1234 AND network
lsf -d 0-10                   # FD range 0-10
lsf -c '/nginx|apache/'       # regex command match
lsf -s TCP:LISTEN             # sockets in LISTEN state
lsf -V -p 999                 # report search items that matched nothing

lsof Option Compatibility

lsofrs parses the full lsof(8) option grammar (getopt clusters plus the +/- prefix family and attached arguments like -o9, -sTCP:LISTEN, +L1).

lsf -l                        # numeric UID instead of login name
lsf -o                        # always show file offset (-o9 = 9 digits)
lsf -s                        # always show file size
lsf +c 0                      # unlimited command column width (0 = no truncation)
lsf -T                        # TCP/TPI info (state shown by default)
lsf -v                        # version (lsof -v); -V reports unfound search items

Legacy/platform-only options are accepted and silently ignored for drop-in script compatibility: -A -b -C -D +|-E +|-e +|-f -K -k +|-m +|-M -O -S -x +|-X -z -Z.


[0x03] ADVANCED MODES

Unified TUI (--tui)

Full-screen tabbed dashboard with all modes in one interface. 7 clickable tabs, 31 color themes, mouse support, hover/right-click tooltips, theme chooser + editor, config persistence.

lsf --tui                     # launch TUI (restores last tab/theme)
lsf --tui --theme matrix      # launch with Matrix theme
sudo lsf --tui                # full visibility (all processes)

Tabs: TOP | SUMMARY | PORTS | TREE | NET-MAP | PIPES | STALE — click or press Tab/1-7 to switch.

Bottom bar: ▶▶▶ LSOFRS ◀◀◀ │ procs:N │ files:N │ tcp:N udp:N unix:N pipe:N │ rate:Ns │ theme:Name │ paused:no │ h=help │ HH:MM:SS — each segment is a hover zone with verbose tooltips.

Mouse: click tabs, scroll rows, right-click for detailed tooltips (PID, FD breakdown, kill hints, copy hints), hover 1s for auto-tooltips.

Theme chooser (c): browse 31 themes with color swatches, live preview as you scroll, Enter to apply + save.

Theme editor (C): create custom 6-color palettes, adjust values 0-255, name and save to ~/.lsofrs.conf.

Top-N Dashboard (--top)

Live auto-refreshing dashboard of the top processes sorted by FD count. Like iotop for file descriptors — shows FD type distribution bars, delta tracking, and per-process breakdowns.

lsf --top                     # top 20 processes by FD count
lsf --top 10                  # top 10 only
lsf --top -r 5                # refresh every 5 seconds
lsf --top -u root             # top FD consumers for root

Top-specific keys: s cycle sort, r reverse, +/- show more/fewer, b toggle bar, d toggle delta. See Interactive Controls for common keys.

File Watch (--watch FILE)

Monitor who opens and closes a specific file over time. Prints timestamped +OPEN/-CLOSE events as they happen — like a lightweight inotifywait / fs_usage for a single path.

lsf --watch /var/log/syslog          # watch syslog
lsf --watch /tmp/myapp.sock          # watch a socket file
lsf --watch /dev/null -r 2           # poll every 2 seconds

Each event shows timestamp, open/close tag, PID, user, FD, and command. When piped, prints a single snapshot and exits.

Stale FDs (--stale)

Find file descriptors pointing to deleted files — a common source of disk space leaks, zombie file handles, and security issues.

lsf --stale                   # find all deleted-file FDs
lsf --stale -u www-data       # deleted files held by www-data
lsf --stale --json            # JSON output
lsf +L1                       # lsof-native equivalent: files with link count < 1

Listening Ports (--ports)

Quick "what's listening where" summary — like ss -tlnp but cross-platform (macOS + Linux).

lsf --ports                   # show all listening TCP/UDP ports
lsf --ports --json            # JSON output
lsf --ports -u root           # ports opened by root only

Pipe Chain (--pipe-chain)

Trace pipe and unix socket pairs between processes — visualize the IPC topology.

lsf --pipe-chain              # show all inter-process pipe/socket connections
lsf --pipe-chain --json       # JSON output
lsf --pipe-chain -c Chrome    # pipes within Chrome process tree

Network Map (--net-map)

Group network connections by remote host — see which servers your system talks to and how many connections each has.

lsf --net-map                 # connections grouped by remote host
lsf --net-map --json          # JSON output
lsf --net-map -u wizard       # only wizard's connections

CSV Export (--csv)

Pure CSV output for pipelines, spreadsheets, and data analysis. RFC 4180-compliant quoting.

lsf --csv                     # full CSV dump
lsf --csv -i TCP              # CSV of TCP connections only
lsf --csv -p 1234 > out.csv   # export PID 1234 to file

Process Tree (--tree)

Hierarchical process tree view with FD counts, type breakdowns, and network connection counts. Like pstree meets lsof.

lsf --tree                    # full process tree with FD stats
lsf --tree -u root            # tree for root's processes
lsf --tree -c Chrome          # tree for Chrome and helpers
lsf --tree --json             # JSON tree with nested children

Each node shows: PID, user, FD count, command name, type breakdown ([REG:12 IPv4:3 PIPE:2]), and network connection count. Notable files (sockets, pipes) are listed inline under each process.

Live Monitor (--monitor / -W)

Full-screen alternate-buffer display like top(1). Auto-refreshes with interactive controls.

lsf --monitor                 # full-screen monitor
lsf -W -r 2                   # refresh every 2 seconds
lsf -W -c Chrome              # monitor Chrome only

Controls: s=sort, r=reverse, f=filter, p=pause, ?=help, q=quit

Follow Mode (--follow PID)

Watch a single process's FDs in real-time. New opens highlighted +NEW in green, closes -DEL in red.

lsf --follow 1234             # watch PID 1234
lsf --follow 1234 -r 2        # 2-second refresh

FD Leak Detection (--leak-detect)

Monitors per-process FD counts over time. Flags processes with monotonically increasing FD counts.

lsf --leak-detect             # default: 5s interval, 3 increase threshold
lsf --leak-detect=10,5        # 10s interval, flag after 5 consecutive increases
lsf --leak-detect -u wizard   # monitor only wizard's processes

Socket Backpressure (--stall)

Polls each socket FD's kernel send/recv buffer occupancy across successive samples and issues a directional verdict per (pid, fd):

  • TX-STALLED — send buffer persistently near capacity and not draining: the peer (or the network) is not reading.
  • RX-STARVED — recv buffer persistently high and growing: the local process is not read()-ing fast enough.
  • HEALTHY — neither buffer is backed up.

macOS reports both queue occupancy and buffer limits, so classification is fill-ratio based. On Linux the queue occupancies come from /proc/net/tcp (buffer limits are unavailable there), so the classifier uses a trend rule (persistently non-zero and non-draining/growing).

lsf --stall                   # single scan, then poll on the default interval
lsf --stall -r 2              # sample every 2s
lsf --stall -i TCP -c myapp   # only myapp's TCP sockets

Summary / Statistics (--summary)

Aggregate FD breakdown with bar charts, top processes, per-user totals. Add -r N for live auto-refreshing TUI mode.

lsf --summary                 # text report (single-shot)
lsf --summary -r 2            # live TUI, refresh every 2s
lsf --summary --json          # JSON report
lsf --summary -i              # network-only summary

Delta Highlighting (--delta)

Color-code changes between repeat iterations. New FDs in green, gone in red.

lsf --delta -r 2              # repeat every 2s with change highlighting
lsf --delta -r 1 -c myapp     # watch myapp changes

[0x04] CYBERPUNK THEME

When output goes to a TTY, lsofrs activates cyberpunk-themed column headers and ANSI coloring:

PipedTTY
COMMANDPROCESS
PIDPRC
USERH4XOR
TYPECL4SS
DEVICEDEV/ICE
SIZE/OFFBYT3/0FF
NODEN0DE
NAMET4RGET

When piped or redirected, plain headers and no colors are used — safe for scripts.


[0x05] INTERACTIVE CONTROLS

All live TUI modes (--tui, --top, --summary -r) share common keybindings.

Common keys:

KeyAction
1-9Set refresh interval (seconds)
</>Fine-adjust refresh interval (±1s)
pPause/resume data collection
?/hToggle help overlay
cOpen theme chooser (31 themes with swatches)
COpen theme editor (custom 6-color palettes)
TToggle hover tooltips (right-click still works)
xToggle border
tToggle compact/expanded view
oFreeze/unfreeze sort order
/Filter popup (regex search)
0Clear filter
j/k//Navigate rows
FPin/unpin selected row
yCopy selected row to clipboard (pbcopy/wl-copy/xclip/xsel, falling back to the OSC 52 terminal escape over ssh)
eExport current tab to file
q/Esc/Ctrl-CQuit

--tui additional keys:

KeyAction
Tab/Next tab
BackTab/Previous tab
1-7Jump to tab by number
Click tabSwitch to clicked tab
Right-click rowVerbose tooltip (PID, FDs, kill hints)
Hover 1sAuto-tooltip (disappears on mouse move)

--top additional keys:

KeyAction
sCycle sort column (FDs→PID→USER→REG→SOCK→PIPE→OTHER→DELTA→CMD)
rReverse sort order
+/-Show more/fewer processes (±5)
bToggle distribution bar column
dToggle delta column

Non-TTY (piped) output always does a single-shot print and exits — no TUI, no key handling.


[0x06] ARCHITECTURE

src/
├── main.rs      # Binary entry point — a two-line call into `lsofrs::run()`
├── lib.rs       # Library crate root — module declarations
├── run.rs       # CLI dispatch, repeat/leak-detect loops (shared with the `lsof` alias crate)
├── cli.rs       # clap argument definitions + custom help display
├── types.rs     # Core data structures (Process, OpenFile, SocketInfo, etc.)
├── darwin.rs    # macOS libproc FFI — process/FD enumeration (rayon parallel)
├── linux.rs     # Linux /proc filesystem — process/FD enumeration (rayon parallel)
├── freebsd.rs   # FreeBSD sysctl + procfs — process/FD enumeration
├── filter.rs    # Selection & filtering (PID, user, command, FD, network)
├── strutil.rs   # Safe UTF-8 truncation for fixed-width display (no mid-codepoint slices)
├── output.rs    # Columnar & field output formatting, ANSI theming
├── json.rs      # JSON serialization via serde
├── resolve.rs   # Cached, parallel host/service name resolution for socket names
├── monitor.rs   # Live full-screen mode (crossterm alternate screen)
├── follow.rs    # Single-process FD tracking with status transitions
├── leak.rs      # Circular-buffer leak detector
├── stall.rs     # Per-FD socket backpressure classifier (TX-STALLED / RX-STARVED)
├── delta.rs     # Iteration-diff engine for change highlighting
├── summary.rs   # Aggregate statistics with bar charts
├── tree.rs      # Process tree view with FD inheritance
├── tui_app.rs   # Shared TUI framework (TuiMode trait, ratatui)
├── tui_tabs.rs  # Unified tabbed TUI (--tui) with 7 tabs, mouse, tooltips
├── theme.rs     # 31 color themes + custom theme support
├── config.rs    # TOML config persistence (~/.lsofrs.conf)
├── top.rs       # Live top-N FD dashboard (TuiMode)
├── watch.rs     # File watch — monitor opens/closes over time
├── stale.rs     # Stale FD finder — deleted files still held open
├── ports.rs     # Listening ports summary (like ss -tlnp)
├── pipe_chain.rs # Pipe/socket IPC topology between processes
├── csv_out.rs   # CSV export (RFC 4180)
└── net_map.rs   # Network connections grouped by remote host
man/man1/
├── lsofrs.1     # Man page — short reference (roff)
└── lsofrsall.1  # Man page — full reference (roff)
completions/
└── _lsofrs      # Zsh completion function

Shell Completions

Zsh completions are provided in completions/_lsofrs. To install:

cp completions/_lsofrs /usr/local/share/zsh/site-functions/
# or symlink into your fpath
ln -sf "$PWD/completions/_lsofrs" /usr/local/share/zsh/site-functions/_lsofrs
# then reload
autoload -Uz compinit && compinit

Platform Support

Supports macOS/Darwin (libproc FFI), Linux (/proc filesystem), and FreeBSD (sysctl + procfs). Platform modules are gated behind #[cfg(target_os)]. Process gathering is parallelized with rayon.

Key Design Decisions

  • Zero-copy FFI: Raw repr(C) structs matched to Darwin kernel headers. No intermediate parsing.
  • Parallel gathering: Per-PID FD enumeration parallelized with rayon.
  • Streaming output: Processes are gathered, filtered, and printed in a single pass.
  • Shared TUI framework: TuiMode trait — all live modes get common keybindings, alternate screen, and atomic frame rendering.
  • serde for JSON: Derive-based serialization, no hand-rolled escaping.
  • clap for CLI: Derive-based argument parsing with full help generation.

[0x07] PERFORMANCE

Benchmarked on macOS with hyperfine (10 runs, 3 warmup, ~470 processes / ~5000 open files, rayon parallel gathering):

All Open Files (default)

ToolMeanMin–MaxSpeedup
lsofrs (Rust)14.2 ms13.6–15.0 ms
lsof 4.91 (C)169.8 ms162.7–176.5 ms12x slower
lsofng (C)173.0 ms169.6–178.3 ms12x slower

Network Connections (-i TCP)

ToolMeanMin–MaxSpeedup
lsofrs7.2 ms6.5–7.8 ms
lsofng88.1 ms86.7–89.4 ms12x slower
lsof 4.9191.7 ms89.6–93.2 ms13x slower

Terse Output (-t, PIDs only)

ToolMeanMin–MaxSpeedup
lsofrs6.9 ms6.2–8.3 ms
lsof 4.91101.4 ms97.5–107.2 ms15x slower
lsofng142.9 ms135.6–150.2 ms21x slower

Structured Output (-J JSON / -F field)

ToolMeanMin–MaxSpeedup
lsofrs -J29.3 ms27.7–31.3 ms
lsofng -J136.7 ms120.8–152.6 ms5x slower
lsof -F pcfn156.1 ms150.3–162.4 ms5x slower

The rayon-parallelized per-PID FD enumeration combined with zero-copy FFI structs and OnceCell-cached username lookups gives lsofrs a 5–21x advantage over traditional lsof implementations.


[0x08] LICENSE

MIT License — MenkeTechnologies


[0xFF] CREDITS

Rust rewrite of lsofng by MenkeTechnologies, which itself is a modernized fork of the original lsof by Vic Abell.