<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark light">
<meta name="description" content="lsofrs — modern Rust implementation of lsof. 5–21× faster than lsof / lsofng. 23,441 lines of production Rust, 1,662 tests, 31 cyberpunk themes, 7-tab TUI, macOS + Linux + FreeBSD, zero-copy FFI, rayon parallel gathering.">
<title>lsofrs — Documentation</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700;900&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<link rel="stylesheet" href="hud-static.css">
<link rel="stylesheet" href="tutorial.css">
<style>
.tutorial-main { max-width: 68rem; }
.docs-build-line {
margin: 0.35rem 0 0;
font-family: 'Share Tech Mono', ui-monospace, monospace;
font-size: 11px;
color: var(--text-dim);
letter-spacing: 0.03em;
max-width: 42rem;
opacity: 0.75;
}
.hub-scheme-strip {
border-bottom: 1px dashed var(--border);
background: color-mix(in srgb, var(--bg-secondary) 85%, transparent);
padding: 0.55rem 1.5rem 0.65rem;
position: relative;
}
.hub-scheme-strip-inner {
max-width: 68rem;
margin: 0 auto;
display: flex;
align-items: center;
gap: 0.85rem;
}
.hub-scheme-strip .hud-scheme-label {
flex: 0 0 auto;
font-family: 'Orbitron', sans-serif;
font-size: 9px;
font-weight: 700;
letter-spacing: 2px;
text-transform: uppercase;
color: var(--accent);
text-align: left;
}
.hub-scheme-strip .scheme-grid {
flex: 1 1 auto;
display: grid;
grid-template-columns: repeat(5, minmax(0, 1fr));
gap: 6px;
}
@media (max-width: 720px) {
.hub-scheme-strip-inner { flex-direction: column; align-items: stretch; }
.hub-scheme-strip .scheme-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.reflection-table {
width: 100%;
border-collapse: collapse;
margin: 0.6rem 0 0.2rem;
font-size: 12px;
}
.reflection-table th {
background: var(--bg-secondary);
color: var(--cyan);
font-family: 'Orbitron', sans-serif;
font-size: 10px;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
text-align: left;
padding: 6px 10px;
border: 1px solid var(--border);
}
.reflection-table td {
padding: 6px 10px;
border: 1px solid var(--border);
color: var(--text-dim);
vertical-align: top;
}
.reflection-table td code { color: var(--accent-light); background: var(--bg); }
.oneliner {
margin: 0.4rem 0;
padding: 0.55rem 0.8rem;
border-left: 2px solid var(--cyan);
background: var(--bg);
font-family: 'Share Tech Mono', ui-monospace, monospace;
font-size: 12px;
color: var(--text);
white-space: pre-wrap;
word-break: break-word;
}
.oneliner .comment { color: var(--text-muted); }
.cat-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
gap: 0.6rem;
margin: 0.7rem 0;
}
.cat-card {
border: 1px solid var(--border);
border-left: 2px solid var(--cyan);
padding: 0.6rem 0.8rem;
background: color-mix(in srgb, var(--bg-card) 92%, transparent);
border-radius: 2px;
}
.cat-card h4 {
font-family: 'Orbitron', sans-serif;
font-size: 11px;
font-weight: 700;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--cyan);
margin: 0 0 0.35rem;
}
.cat-card p {
margin: 0;
font-size: 11.5px;
color: var(--text-dim);
line-height: 1.5;
}
.cat-card code { font-size: 11px; color: var(--accent-light); }
</style>
</head>
<body>
<div class="app tutorial-app" id="docsApp">
<div class="crt-scanline" id="crtH" aria-hidden="true"></div>
<div class="crt-scanline-v" id="crtV" aria-hidden="true"></div>
<header class="tutorial-header">
<div class="tutorial-header-inner">
<div>
<h1 class="tutorial-brand">// LSOFRS — LIST SYSTEM OPEN FILES IN RUST</h1>
<nav class="tutorial-crumbs" aria-label="Breadcrumb">
<span class="current">Docs</span>
<span class="sep">/</span>
<a href="report.html">Engineering report</a>
<span class="sep">/</span>
<a href="https://github.com/MenkeTechnologies/lsofrs" target="_blank" rel="noopener noreferrer">GitHub</a>
<span class="sep">/</span>
<a href="https://crates.io/crates/lsofrs" target="_blank" rel="noopener noreferrer">crates.io</a>
<span class="sep">/</span>
<a href="https://docs.rs/lsofrs" target="_blank" rel="noopener noreferrer">docs.rs</a>
</nav>
<p class="docs-build-line">lsofrs v4.8.5 · Zero-copy FFI · Rayon-parallel gathering · macOS + Linux + FreeBSD · 7-tab TUI · 31 cyberpunk themes · 5–21× faster than lsof / lsofng</p>
<p class="docs-build-line">23,441 Rust src · 8,560 test src · 1,662 #[test] functions · 13 direct dependencies</p>
</div>
<div class="tutorial-toolbar">
<button type="button" class="btn btn-secondary" id="btnTheme" title="Toggle light/dark">Theme</button>
<button type="button" class="btn btn-secondary active" id="btnCrt" title="CRT scanline overlay">CRT</button>
<button type="button" class="btn btn-secondary active" id="btnNeon" title="Neon border pulse">Neon</button>
<a class="btn btn-secondary" href="report.html">Report</a>
<a class="btn btn-secondary" href="https://github.com/MenkeTechnologies/lsofrs" target="_blank" rel="noopener noreferrer">GitHub</a>
<a class="btn btn-secondary" href="https://github.com/MenkeTechnologies/lsofrs/issues" target="_blank" rel="noopener noreferrer">Issues</a>
</div>
</div>
</header>
<div class="hub-scheme-strip">
<div class="hub-scheme-strip-inner">
<span class="hud-scheme-label">// Color scheme</span>
<div class="scheme-grid" id="hudSchemeGrid"></div>
</div>
</div>
<main class="tutorial-main">
<h2 class="tutorial-title"><span class="step-hash">>_</span>LSOFRS — THE FASTEST LSOF EVER WRITTEN</h2>
<p class="tutorial-subtitle"><strong>Maps the invisible topology between processes and the files they hold open.</strong> Regular files, directories, sockets, pipes, devices, kqueues — anything the kernel touches. Rust rewrite of <code>lsofng</code> with zero-copy <code>repr(C)</code> FFI to Darwin / Linux / FreeBSD kernel headers, rayon work-stealing across every CPU for per-PID FD enumeration, and a single streaming pass from gather → filter → print. <strong>14.2 ms wall-clock</strong> vs lsof's 169.8 ms on a ~470-process / ~5000-FD macOS box (<code>hyperfine</code>, 10 runs, 3 warmup).</p>
<section class="tutorial-section">
<h2>Quickstart</h2>
<p>Install from crates.io or source. The same binary is published twice — <code>lsofrs</code> (long) and <code>lsf</code> (short, quicker to type):</p>
<pre># install
cargo install lsofrs
# from source
git clone https://github.com/MenkeTechnologies/lsofrs
cd lsofrs && cargo build --release
sudo cp target/release/lsf /usr/local/sbin/
# everyday queries
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)
# pipelines
lsf --json | jq '.[] | select(.fd == "cwd")'
lsf --csv > snapshot.csv
lsf -F pcfn # field output (p=pid, c=cmd, f=fd, n=name)</pre>
<p>Full install + usage live in the <a href="https://github.com/MenkeTechnologies/lsofrs#readme">README</a>. Man page: <code>man lsofrs</code> (310-line roff under <code>lsofrs.1</code>). Zsh completion ships under <code>completions/_lsofrs</code>.</p>
</section>
<section class="tutorial-section">
<h2>Why lsofrs — Wall-Clock Comparison</h2>
<p>Benchmarked on macOS with <code>hyperfine</code> (10 runs, 3 warmup, ~470 processes / ~5000 open files). Numbers are reproducible from <a href="https://github.com/MenkeTechnologies/lsofrs#-performance">README §PERFORMANCE</a>.</p>
<table class="comparison-table" style="width:100%; border-collapse:collapse; font-size:0.85em;">
<thead>
<tr style="border-bottom:2px solid #0ff;">
<th style="text-align:left; padding:4px;">Workload</th>
<th style="padding:4px;">lsofrs (Rust)</th>
<th style="padding:4px;">lsof 4.91 (C)</th>
<th style="padding:4px;">lsofng (C)</th>
<th style="padding:4px;">Speedup</th>
</tr>
</thead>
<tbody>
<tr><td>All open files (default)</td><td style="color:#0f0;"><b>14.2 ms</b></td><td>169.8 ms</td><td>173.0 ms</td><td style="color:#0f0;">12×</td></tr>
<tr><td>Network only (<code>-i TCP</code>)</td><td style="color:#0f0;"><b>7.2 ms</b></td><td>91.7 ms</td><td>88.1 ms</td><td style="color:#0f0;">12–13×</td></tr>
<tr><td>Terse PIDs (<code>-t</code>)</td><td style="color:#0f0;"><b>6.9 ms</b></td><td>101.4 ms</td><td>142.9 ms</td><td style="color:#0f0;">15–21×</td></tr>
<tr><td>Structured (<code>-J</code> JSON / <code>-F</code> field)</td><td style="color:#0f0;"><b>29.3 ms</b></td><td>156.1 ms</td><td>136.7 ms</td><td style="color:#0f0;">5×</td></tr>
</tbody>
</table>
<h3 style="margin-top:1em;">Feature parity vs incumbents</h3>
<table class="comparison-table" style="width:100%; border-collapse:collapse; font-size:0.85em;">
<thead>
<tr style="border-bottom:2px solid #0ff;">
<th style="text-align:left; padding:4px;">Feature</th>
<th style="padding:4px;">lsofrs</th>
<th style="padding:4px;">lsof</th>
<th style="padding:4px;">lsofng</th>
<th style="padding:4px;">fuser</th>
<th style="padding:4px;">ss</th>
</tr>
</thead>
<tbody>
<tr><td>Built-in JSON (<code>--json</code> / <code>-J</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✓</td><td>✗</td><td>✗</td></tr>
<tr><td>Built-in CSV (<code>--csv</code>, RFC 4180)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Field output (<code>-F</code>)</td><td style="color:#0f0;">✓</td><td>✓</td><td>✓</td><td>✗</td><td>✗</td></tr>
<tr><td>Full-screen tabbed TUI (<code>--tui</code>)</td><td style="color:#0f0;">7 tabs</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Top-N FD dashboard (<code>--top</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Stale-FD finder (<code>--stale</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Listening-ports view (<code>--ports</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✓</td></tr>
<tr><td>Process tree (<code>--tree</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Pipe / unix-socket IPC map (<code>--pipe-chain</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Net-by-remote-host map (<code>--net-map</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>File-open/close watch (<code>--watch</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>FD-leak detector (<code>--leak-detect</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Single-process follow (<code>--follow</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Delta highlighting (<code>--delta</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Aggregate summary + bar charts (<code>--summary</code>)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Themeable output (31 palettes)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Parallel per-PID gather (rayon)</td><td style="color:#0f0;">✓</td><td>✗</td><td>✗</td><td>✗</td><td>✗</td></tr>
<tr><td>Cross-platform (Darwin + Linux + FreeBSD)</td><td style="color:#0f0;">✓</td><td>✓</td><td>✓</td><td>Linux/BSD</td><td>Linux</td></tr>
</tbody>
</table>
</section>
<section class="tutorial-section">
<h2>Overview</h2>
<ul>
<li><strong>CLI front-end</strong> — clap derive parser in <code>src/cli.rs</code> (1,341 lines, 38 <code>#[arg(...)]</code> attributes). <code>main.rs</code> dispatches to the active mode based on which flag is set.</li>
<li><strong>Platform gather</strong> — <code>src/darwin.rs</code> (1,253 lines, libproc FFI), <code>src/linux.rs</code> (820 lines, <code>/proc</code> reader), <code>src/freebsd.rs</code> (835 lines, sysctl + procfs). All three return the same <code>Vec<Process></code> from <code>types.rs</code>; each per-PID FD scan is parallelized with rayon's work-stealing pool.</li>
<li><strong>Selection</strong> — <code>src/filter.rs</code> (2,812 lines) implements OR-mode (default) and AND-mode (<code>-a</code>) filter composition over PID / PGID / user / command / FD / network-spec / path. Supports comma-lists, ranges (<code>0-10</code>), exclusion (<code>^root</code>), and regex (<code>/nginx|apache/</code>).</li>
<li><strong>Output</strong> — <code>src/output.rs</code> (columnar + field), <code>src/json.rs</code> (serde), <code>src/csv_out.rs</code> (RFC 4180). TTY detection auto-switches between cyberpunk headers (<code>H4XOR</code> / <code>CL4SS</code> / <code>T4RGET</code>) and plain headers for pipelines.</li>
<li><strong>Live modes</strong> — <code>--tui</code> (7-tab dashboard, 5,312 lines), <code>--top</code> (1,008 lines), <code>--summary -r</code> (904 lines), <code>--monitor</code> (288 lines), <code>--watch FILE</code>, <code>--follow PID</code>, <code>--leak-detect</code>. All share <code>src/tui_app.rs</code>'s <code>TuiMode</code> trait for common keybindings, alternate-screen entry/exit, and atomic frame rendering.</li>
<li><strong>Themes</strong> — <code>src/theme.rs</code> (1,005 lines) defines 31 named palettes via the <code>ThemeName</code> enum. Custom 6-color themes persist to <code>~/.lsofrs.conf</code> through <code>src/config.rs</code> (TOML).</li>
</ul>
</section>
<section class="tutorial-section">
<h2>Modes — one card per entry point</h2>
<div class="cat-grid">
<div class="cat-card"><h4>--tui</h4><p>Unified 7-tab dashboard: <code>TOP</code> / <code>SUMMARY</code> / <code>PORTS</code> / <code>TREE</code> / <code>NET-MAP</code> / <code>PIPES</code> / <code>STALE</code>. Click tabs, mouse-hover for tooltips, right-click for verbose detail (PID, FD breakdown, kill / copy hints). Theme chooser (<code>c</code>) + editor (<code>C</code>).</p></div>
<div class="cat-card"><h4>--top [N]</h4><p>Live auto-refreshing top-N processes sorted by FD count. FD-type distribution bar, delta tracking, per-process breakdown. <code>s</code> cycles sort column, <code>+/-</code> grows/shrinks N.</p></div>
<div class="cat-card"><h4>--summary [-r N]</h4><p>Aggregate FD breakdown with bar charts, top processes, per-user totals. With <code>-r N</code> becomes a live TUI; <code>--json</code> emits a structured report; <code>-i</code> restricts to network FDs.</p></div>
<div class="cat-card"><h4>--ports</h4><p>Quick "what's listening where" summary — like <code>ss -tlnp</code> but cross-platform (macOS + Linux + FreeBSD). <code>--json</code> and per-user filtering supported.</p></div>
<div class="cat-card"><h4>--tree</h4><p>Hierarchical process tree with FD counts, per-PID type breakdown (<code>[REG:12 IPv4:3 PIPE:2]</code>), network connection counts, and notable open files inline.</p></div>
<div class="cat-card"><h4>--net-map</h4><p>Network connections grouped by remote host — fastest way to see which servers your box talks to and how many sockets each peer holds.</p></div>
<div class="cat-card"><h4>--pipe-chain</h4><p>Trace pipe and unix-socket pairs between processes — visualize the IPC topology that <code>ps</code> and <code>top</code> hide.</p></div>
<div class="cat-card"><h4>--stale</h4><p>Find FDs pointing to deleted files. Common source of disk-space leaks, zombie handles, and security issues (process held an unlinked secret file).</p></div>
<div class="cat-card"><h4>--watch FILE</h4><p>Print timestamped <code>+OPEN</code> / <code>-CLOSE</code> events for a single path. Lightweight <code>inotifywait</code> / <code>fs_usage</code> equivalent that runs on macOS, Linux, and FreeBSD.</p></div>
<div class="cat-card"><h4>--follow PID</h4><p>Watch one process's FDs in real time. New opens highlight <code>+NEW</code> (green), closes <code>-DEL</code> (red).</p></div>
<div class="cat-card"><h4>--leak-detect[=I,N]</h4><p>Sample per-process FD counts every <code>I</code> seconds; flag any PID whose count rises <code>N</code> consecutive intervals in a row. Circular buffer per PID in <code>src/leak.rs</code>.</p></div>
<div class="cat-card"><h4>--delta -r N</h4><p>Color-code changes between repeat iterations. New FDs in green, removed in red — useful inside <code>watch</code>-style loops without the noise of full re-prints.</p></div>
<div class="cat-card"><h4>--monitor / -W</h4><p>Classic full-screen alternate-buffer monitor like <code>top(1)</code>. <code>s</code> sort / <code>r</code> reverse / <code>f</code> filter / <code>p</code> pause / <code>?</code> help.</p></div>
<div class="cat-card"><h4>--csv</h4><p>Pure RFC-4180 CSV dump for pipelines and spreadsheets. Composes with every selector — <code>lsf --csv -i TCP -u root > root_tcp.csv</code>.</p></div>
<div class="cat-card"><h4>--json / -J</h4><p>Serde-backed JSON array. Composes with every selector. Each element carries the full <code>OpenFile</code> shape from <code>src/types.rs</code> (PID, command, FD, type, device, size/offset, node, name, plus parsed socket / protocol fields when present).</p></div>
<div class="cat-card"><h4>-F <chars></h4><p>Per-record field output for scripting (compat with the original lsof). <code>p</code>=pid, <code>c</code>=command, <code>f</code>=fd, <code>n</code>=name, <code>t</code>=type, etc.</p></div>
</div>
</section>
<section class="tutorial-section">
<h2>Selection grammar</h2>
<p>Every selector is independent and composable. By default selectors OR together; <code>-a</code> switches the entire predicate to AND mode. Negation via <code>^</code>, ranges via <code>N-M</code>, regex via <code>/…/</code>.</p>
<pre>lsf -p 1234,5678 # PIDs 1234 OR 5678
lsf -u root,wizard # users root OR wizard
lsf -p ^1234 # everything except PID 1234
lsf -u ^root # everything except root
lsf -d 0-10 # FDs 0 through 10
lsf -c '/nginx|apache/' # command name matches regex
lsf -a -p 1234 -i # AND: PID 1234 AND has network FD
lsf -a -u nginx -i TCP:443 # AND: nginx user AND TCP/443
lsf -i # any network FD
lsf -i 4 # IPv4 only
lsf -i 6 # IPv6 only
lsf -i TCP # TCP only
lsf -i :443 # any protocol on port 443
lsf -i TCP:443 # TCP on port 443</pre>
</section>
<section class="tutorial-section">
<h2>Cyberpunk theming</h2>
<p>When stdout is a TTY, column headers swap from utilitarian (<code>COMMAND</code> / <code>PID</code> / <code>USER</code>) to cyberpunk (<code>PROCESS</code> / <code>PRC</code> / <code>H4XOR</code>) and ANSI coloring activates. Piped output is always plain — safe for scripts. 31 named palettes ship in <code>src/theme.rs</code>:</p>
<table class="reflection-table">
<thead><tr><th>Palette family</th><th>Themes</th></tr></thead>
<tbody>
<tr><td>Neon / synth</td><td><code>NeonSprawl</code> (default), <code>NeonNoir</code>, <code>Synthwave</code>, <code>GlitchPop</code>, <code>HoloShift</code></td></tr>
<tr><td>Matrix / phosphor</td><td><code>Matrix</code>, <code>AcidRain</code>, <code>BioHazard</code>, <code>ToxicWaste</code></td></tr>
<tr><td>Blade Runner / noir</td><td><code>BladeRunner</code>, <code>NightCity</code>, <code>Megacorp</code>, <code>Zaibatsu</code>, <code>VoidWalker</code>, <code>Darkwave</code>, <code>DarkSignal</code></td></tr>
<tr><td>Frost / ice</td><td><code>IceBreaker</code>, <code>CyberFrost</code>, <code>GhostWire</code>, <code>ChromeHeart</code>, <code>SteelNerve</code>, <code>QuantumFlux</code></td></tr>
<tr><td>Solar / ember</td><td><code>SolarFlare</code>, <code>PlasmaCore</code>, <code>LaserGrid</code>, <code>RedSector</code>, <code>SakuraDen</code></td></tr>
<tr><td>Data / minimal</td><td><code>Classic</code>, <code>DeepNet</code>, <code>DataStream</code>, <code>Overlock</code></td></tr>
</tbody>
</table>
<p>Inside any TUI mode press <code>c</code> for the theme chooser (live preview), <code>C</code> for the 6-color editor. Selections persist to <code>~/.lsofrs.conf</code> via <code>src/config.rs</code>.</p>
</section>
<section class="tutorial-section">
<h2>Interactive controls (shared across TUI modes)</h2>
<table class="reflection-table">
<thead><tr><th>Key</th><th>Action</th></tr></thead>
<tbody>
<tr><td><code>1</code>–<code>9</code></td><td>Set refresh interval (seconds)</td></tr>
<tr><td><code><</code> / <code>></code></td><td>Fine-adjust refresh interval (±1s)</td></tr>
<tr><td><code>p</code></td><td>Pause / resume data collection</td></tr>
<tr><td><code>?</code> / <code>h</code></td><td>Toggle help overlay</td></tr>
<tr><td><code>c</code> / <code>C</code></td><td>Theme chooser / editor</td></tr>
<tr><td><code>T</code></td><td>Toggle hover tooltips (right-click still works)</td></tr>
<tr><td><code>x</code></td><td>Toggle border</td></tr>
<tr><td><code>t</code></td><td>Toggle compact / expanded view</td></tr>
<tr><td><code>o</code></td><td>Freeze / unfreeze sort order</td></tr>
<tr><td><code>/</code> / <code>0</code></td><td>Filter popup (regex) / clear filter</td></tr>
<tr><td><code>j</code> / <code>k</code> / <code>↑</code> / <code>↓</code></td><td>Navigate rows</td></tr>
<tr><td><code>F</code></td><td>Pin / unpin selected row</td></tr>
<tr><td><code>y</code></td><td>Copy selected row to clipboard</td></tr>
<tr><td><code>e</code></td><td>Export current tab to file</td></tr>
<tr><td><code>q</code> / <code>Esc</code> / <code>Ctrl-C</code></td><td>Quit</td></tr>
</tbody>
</table>
<p><code>--tui</code> adds tab navigation (<code>Tab</code> / <code>BackTab</code> / <code>1</code>–<code>7</code> / click). <code>--top</code> adds <code>s</code> sort, <code>r</code> reverse, <code>+/-</code> grow/shrink, <code>b</code> bar toggle, <code>d</code> delta toggle.</p>
</section>
<section class="tutorial-section">
<h2>Architecture in one screen</h2>
<pre>src/
├── main.rs # 282 CLI entry, mode dispatch, repeat/leak loops
├── cli.rs # 1,341 clap derive args (38 #[arg], 20 short flags)
├── types.rs # 867 Process, OpenFile, SocketInfo, NetSpec, …
├── darwin.rs # 1,253 macOS libproc FFI (zero-copy repr(C))
├── linux.rs # 820 /proc reader (parallel per-PID via rayon)
├── freebsd.rs # 835 sysctl + procfs reader
├── filter.rs # 2,812 selection & filter composition (AND/OR, regex)
├── strutil.rs # 76 safe UTF-8 truncation for fixed-width display
├── output.rs # 772 columnar & field formatting, ANSI theming
├── json.rs # serde JSON
├── csv_out.rs # RFC 4180 CSV
├── monitor.rs # 288 classic full-screen alternate-buffer monitor
├── follow.rs # 369 single-PID FD tracker (status transitions)
├── leak.rs # 339 circular-buffer FD-count leak detector
├── delta.rs # iteration-diff engine for change highlighting
├── summary.rs # 904 aggregate stats + bars (+ live TUI mode)
├── tree.rs # 556 process tree w/ FD inheritance
├── tui_app.rs # 564 shared TuiMode trait (ratatui)
├── tui_tabs.rs # 5,312 unified 7-tab TUI (mouse, tooltips)
├── theme.rs # 1,005 31 themes + custom palette support
├── config.rs # TOML config persistence (~/.lsofrs.conf)
├── top.rs # 1,008 live top-N FD dashboard
├── watch.rs # 369 file-open/close watch
├── stale.rs # 313 deleted-file FD finder
├── ports.rs # 450 listening-ports summary
├── pipe_chain.rs # 358 pipe / unix-socket IPC topology
└── net_map.rs # 608 connections grouped by remote host
lsofrs.1 # 310-line roff man page
completions/_lsofrs # 101-line zsh completion (#compdef lsofrs)</pre>
</section>
<section class="tutorial-section">
<h2>Platform support matrix</h2>
<table class="reflection-table">
<thead><tr><th>OS</th><th>Module</th><th>Mechanism</th><th>Status</th></tr></thead>
<tbody>
<tr><td>macOS / Darwin</td><td><code>src/darwin.rs</code> (1,253 lines)</td><td><code>libproc</code> FFI via zero-copy <code>#[repr(C)]</code> structs matching kernel headers; <code>proc_listpids</code> + <code>proc_pidinfo</code> + <code>proc_pidfdinfo</code>.</td><td>Primary platform</td></tr>
<tr><td>Linux</td><td><code>src/linux.rs</code> (820 lines)</td><td><code>/proc/<pid>/{stat,status,fd,fdinfo}</code> reader; parallelized per-PID with rayon.</td><td>Supported</td></tr>
<tr><td>FreeBSD</td><td><code>src/freebsd.rs</code> (835 lines)</td><td><code>sysctl(KERN_PROC_FILEDESC)</code> + <code>/proc</code> when mounted; FreeBSD-specific socket / kqueue decoding.</td><td>Supported</td></tr>
</tbody>
</table>
<p>Each platform module is gated by <code>#[cfg(target_os = "…")]</code> in <code>src/lib.rs</code>. The shared <code>Process</code> / <code>OpenFile</code> / <code>SocketInfo</code> shapes live in <code>src/types.rs</code> (867 lines, 11 public structs / enums) — every gather backend returns the same data, so the entire stack above <code>filter.rs</code> is platform-agnostic.</p>
</section>
<section class="tutorial-section">
<h2>Why it's fast</h2>
<ul>
<li><strong>Zero-copy FFI.</strong> Darwin gather uses raw <code>#[repr(C)]</code> structs sized to kernel headers — no intermediate parse step, no allocator pressure per-FD.</li>
<li><strong>Rayon work-stealing per-PID.</strong> Each PID's FD scan runs on its own worker; CPU count = parallel degree.</li>
<li><strong>Username caching.</strong> v4.8.0 added a <code>OnceCell</code>-backed <code>getpwuid</code> cache — previously the hot loop called the syscall once per record.</li>
<li><strong>Precomputed filter paths.</strong> The filter predicate canonicalizes its lookups once before the gather pass, not per-FD.</li>
<li><strong>Streaming output.</strong> No intermediate <code>Vec<Record></code> for the common path — gather → filter → format → write goes through the same iterator chain.</li>
<li><strong>serde + clap derive.</strong> No hand-rolled JSON escaping, no hand-rolled getopt loop.</li>
</ul>
<p>Net result: <strong>14.2 ms</strong> wall-clock for the default <code>lsf</code> invocation vs <strong>169.8 ms</strong> for <code>lsof 4.91</code> on the same machine (<code>hyperfine</code>, ~470 procs, ~5000 FDs).</p>
</section>
<section class="tutorial-section">
<h2>JSON shape</h2>
<p><code>--json</code> emits an array of records. Each record is the public <code>OpenFile</code> serialization from <code>src/types.rs</code>:</p>
<pre>[
{
"pid": 1234,
"ppid": 1,
"pgid": 1234,
"uid": 0,
"user": "root",
"command": "nginx",
"fd": "10u",
"type": "IPv4",
"device": "0x0",
"size_off": null,
"node": "TCP",
"name": "*:8080 (LISTEN)",
"socket": {
"protocol": "TCP",
"local_addr": "0.0.0.0",
"local_port": 8080,
"remote_addr": null,
"remote_port": null,
"state": "LISTEN"
}
}
]</pre>
<p>Hard-coded JSON contract tests live in <code>tests/json_shape.rs</code>, <code>tests/json_wrappers.rs</code>, and <code>tests/json_and_csv_contracts.rs</code> (233 <code>#[test]</code> functions in the latter alone) — refactors can't silently break downstream consumers.</p>
</section>
<section class="tutorial-section">
<h2>Where to go next</h2>
<ul>
<li><a href="report.html">Engineering report</a> — per-subsystem LOC, top-20 files, dependency table, test surface.</li>
<li><a href="https://github.com/MenkeTechnologies/lsofrs#readme">README</a> — full install, every flag, full benchmark table.</li>
<li><a href="https://docs.rs/lsofrs">docs.rs/lsofrs</a> — rustdoc for the library crate (<code>pub mod cli; pub mod types; pub mod filter; …</code>).</li>
<li><a href="https://github.com/MenkeTechnologies/lsofrs/blob/main/lsofrs.1">lsofrs.1</a> — 310-line roff man page (also <code>man lsofrs</code> after install).</li>
</ul>
</section>
</main>
<footer style="border-top:1px dashed var(--border);padding:1rem 1.5rem;text-align:center;font-family:'Share Tech Mono',ui-monospace,monospace;font-size:11px;color:var(--text-muted);">
lsofrs v4.8.5 · MIT license · built by <a href="https://github.com/MenkeTechnologies">MenkeTechnologies</a> ·
<a href="https://github.com/MenkeTechnologies/lsofrs">GitHub</a> ·
<a href="https://crates.io/crates/lsofrs">crates.io</a> ·
<a href="https://docs.rs/lsofrs">docs.rs</a>
</footer>
</div>
<script src="hud-theme.js"></script>
</body>
</html>