1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
//! macOS `lsof` liveness backend (DESIGN §10): a pure `lsof -F` parser, a
//! trait-injected runner seam, and a `#[cfg(target_os = "macos")]` spawn shim.
//!
//! Linux answers both liveness questions from `/proc` ([`super::fd_probe`],
//! [`super::lock_probe`]); macOS has no `/proc`, so it parses `lsof` output. Per
//! §10 the *parser is pure and platform-independent* — compiled and covered on
//! Linux from recorded fixtures — and **only** the spawn shim is `macos`; that
//! shim is the sole region tarpaulin excludes from the Linux denominator
//! (empirically confirmed: a `cfg(target_os = "macos")` region is not compiled
//! into the instrumented binary, so it cannot be counted).
//!
//! # `lsof -F` field grammar (argv `lsof -F pan -- <path>`)
//!
//! `-F` emits one `<tag><value>` line per field (`man lsof`, "OUTPUT FOR OTHER
//! PROGRAMS"). The tags we select and consume:
//!
//! - `p` — **process ID**; begins a *process set* (always the set's first line).
//! - `f` — **file descriptor**; begins a *file set* (one open file). `pan` does
//! not name `f`, but lsof still delimits file sets; we treat any `f` line as a
//! fresh-file reset for robustness across GNU/BSD builds.
//! - `a` — **file access mode** (`man lsof`, field `a`): `r` read, `w` write,
//! `u` read *and* write; space / `-` unknown. A *writer* is `a` = `w` or `u`.
//! - `n` — **file name**. Compared against the canonicalized target
//! ([`LsofProbe::observe`] canonicalizes before it asks; lsof resolves its
//! own name — canonicalize-both-sides, mirroring the procfs backends).
//!
//! Within a file set `a` precedes `n`, so the access seen since the last file
//! boundary (`f`, `p`, or the previous `n`) is that file's mode. **Confidence:**
//! `-F` is lsof's stable inter-program contract, identical in shape on Linux and
//! macOS/BSD, so the grammar is documented, not guessed; the parser is also
//! tolerant of the `f` field being present or absent.
//!
//! # Failure semantics (§10)
//!
//! `lsof` absent, erroring, or emitting non-field output ⇒ [`Probe::Unknown`]
//! (renders the Y4 "?" badge) — never a false definite. `lsof` exits 1 for both
//! "no match" and real errors, so status alone cannot disambiguate: the shim
//! maps a spawn failure and a non-empty stderr to Unknown, while empty stdout is
//! the definite "no holder" ([`Probe::Free`]).
//!
//! The one error lsof reports that is **not** uncertainty is a target that does
//! not exist, and [`LsofProbe::observe`] settles it before spawning anything —
//! see its doc for why that and the canonical spelling are one question.
use ;
use Path;
/// What an `lsof -F` scan saw about the queried target: whether *any* process
/// holds it open (the lock question) and whether any holder has it open for
/// *write* (the response.json writer question).
/// Parse `lsof -F pan` output, deciding [`Sightings`] for `target`. Returns
/// `None` when the bytes are not `-F` field output — invalid UTF-8, or
/// non-empty content with no process (`p`) set — which the caller maps to
/// [`Probe::Unknown`]. Empty output is a definite "no holder", not an error.
/// Injected `lsof` runner (the trait-injection seam, DESIGN §10 "the
/// trait-injection pattern is the template for every new effect"): yields the
/// raw stdout of `lsof -F pan -- <target>`, or `None` when lsof could not be
/// observed at all (absent / errored). Keeping the spawn behind this seam is
/// what lets the parser and probe be 100 %-covered on Linux with a recorded
/// fixture and a fake runner; only the real macOS runner below is cfg'd out.
pub
/// The macOS liveness backend: answers both probe questions by parsing an
/// injected [`LsofRunner`]'s output. One struct implements both traits because
/// a single `lsof` invocation (over the relevant target) evidences both.
pub
/// The production `lsof` runner: spawns the real binary. macOS-only — the sole
/// code excluded from Linux coverage (§10 CI: "nothing but the lsof spawn shim
/// is cfg'd out").
pub ;
/// Construct the macOS liveness probe: the real `lsof` runner behind a 2 s TTL
/// cache (DESIGN §10). `super::GitTree::from_repo` selects this by `cfg` on
/// macOS; Linux uses the `/proc` probes instead.
pub