diff --git a/src/main/ssh/ssh-relay-endpoint-incumbent.test.ts b/src/main/ssh/ssh-relay-endpoint-incumbent.test.ts index 40d2c49f5d9..2fabd32e584 100644 --- a/src/main/ssh/ssh-relay-endpoint-incumbent.test.ts +++ b/src/main/ssh/ssh-relay-endpoint-incumbent.test.ts @@ -181,7 +181,7 @@ describe('probeRelayEndpointIncumbent', () => { describe('relayEndpointIncumbentProbeCommand', () => { it('ANDs the lsof selectors so it cannot match unrelated unix-socket holders', () => { - expect(RELAY_LSOF_PROBE_JS).toContain("['-t', '-a', '-U', process.argv[1]]") + expect(RELAY_LSOF_PROBE_JS).toContain("['-w', '-t', '-a', '-U', process.argv[1]]") }) it('never unlinks the relay endpoint', () => { diff --git a/src/shared/child-process/posix-lsof-probe.test.ts b/src/shared/child-process/posix-lsof-probe.test.ts index 70c038b12fa..e5db9799a82 100644 --- a/src/shared/child-process/posix-lsof-probe.test.ts +++ b/src/shared/child-process/posix-lsof-probe.test.ts @@ -44,7 +44,12 @@ process.kill = function(pid, signal) { }; ` -async function runProbe(options: { signal?: string; census?: string; censusKillDenied?: boolean }) { +async function runProbe(options: { + signal?: string + census?: string + censusKillDenied?: boolean + lsof?: string +}) { const dir = mkdtempSync(join(tmpdir(), 'orca-lsof-lifecycle-')) const pidFile = join(dir, 'lsof.pid') const psPidFile = join(dir, 'ps.pid') @@ -52,7 +57,7 @@ async function runProbe(options: { signal?: string; census?: string; censusKillD writeFileSync(join(dir, 'preload.cjs'), PRELOAD) writeFileSync( join(dir, 'lsof'), - `#!/bin/sh\necho 123\n${options.signal ? 'exec sleep 60\n' : 'exit 2\n'}`, + options.lsof ?? `#!/bin/sh\necho 123\n${options.signal ? 'exec sleep 60\n' : 'exit 2\n'}`, { mode: 0o755 } ) if (options.census !== undefined) { @@ -111,6 +116,23 @@ async function runProbe(options: { signal?: string; census?: string; censusKillD } describe.skipIf(process.platform === 'win32')('lsof supervisor lifecycle', () => { + it('keeps holder evidence usable when lsof would warn about an unstat-able mount', async () => { + const result = await runProbe({ + lsof: [ + '#!/bin/sh', + 'quiet=', + 'for arg in "$@"; do [ "$arg" = "-w" ] && quiet=1; done', + '[ -z "$quiet" ] && echo "lsof: WARNING: can\'t stat() nfs fs /mnt/stale" >&2', + 'echo 123', + 'exit 0' + ].join('\n') + }) + expect(result).toMatchObject({ code: 0, timedOut: false }) + const [marker, ...pids] = result.stdout.split('\n') + expect(marker).toBe('lsof') + expect(pids.filter(Boolean)).toEqual(['123']) + }) + it.each(['SIGTERM', 'SIGHUP', 'SIGINT'])( 'owns lsof when %s arrives inside spawn', async (signal) => { diff --git a/src/shared/child-process/posix-lsof-probe.ts b/src/shared/child-process/posix-lsof-probe.ts index 858758b7979..8f167ed2aa4 100644 --- a/src/shared/child-process/posix-lsof-probe.ts +++ b/src/shared/child-process/posix-lsof-probe.ts @@ -112,7 +112,7 @@ function cleanup() { ['SIGTERM', 'SIGHUP', 'SIGINT'].forEach(function(signal) { process.on(signal, function() { unavailable = true; cleanup(); }); }); -child = spawn('lsof', ['-t', '-a', '-U', process.argv[1]], { +child = spawn('lsof', ['-w', '-t', '-a', '-U', process.argv[1]], { detached: true, stdio: ['ignore', 'pipe', 'pipe'] });