Skip to content

kill: other users' pid-less rows are skipped, not failed - #17

Merged
pyjeebz merged 3 commits into
mainfrom
fix/kill-skips-unowned
Nov 3, 2026
Merged

pyjeebz merged 3 commits into
mainfrom
fix/kill-skips-unowned

Conversation

@pyjeebz

@pyjeebz pyjeebz commented Nov 2, 2026

Copy link
Copy Markdown
Owner

Closes #4.

ports kill <name> matches every row whose name fits, including other users' listeners. A scan without root sees those with pid 0, and nothing short of sudo can stop them. Each one was reported as a failed stop, so a kill that stopped everything it could still exited 1. A script or agent running ports kill shop && … read that as "the stop didn't work". --dry-run was worse: it claimed it "would stop" those rows and exited 0.

Now, for kill only:

  • Skipped, not failed. Those rows are skipped: still reported, never hidden, each with the command that would stop it. That's sudo systemctl stop <unit> for a named service, sudo ports free <port> otherwise, and ports doctor <port> for a docker-proxy whose container didn't resolve, since sudo can't stop a proxy either.
  • Exit code. A skipped row never fails a kill that stopped what it could. When skipped rows are all there was, nothing was stopped and it exits 1.
  • --expect. The guard judges only what would actually be stopped. A skipped row is never stopped, so it can't sink a guarded kill.

ports free <port> is unchanged. You named that port outright, so failing to stop what holds it is a real failure there.

How it was verified

Gate, locally with CI's versions: unit ✓, build ✓, integration ✓ (uncached), installers ✓, gofmt ✓, vet ✓, lint ✓ (v2.13.2).

Real binary on a machine with a root-owned listener on :2024 (seen as ?, pid 0). I started a python server on :8792 renamed ? so that kill '?' matches both:

main
  ✗ ? (:2024): owned by user root — run with sudo
    → run `ports doctor 2024` to see why
  ✓ stopped ? (:8792)
  exit 1                                  ← the bug
main --dry-run
  would stop ? (:2024)                    ← it couldn't
  would stop ? (:8792)
  exit 0

this branch
  ✓ stopped ? (:8792)
  · skipped ? (:2024): owned by root — its pid is hidden from this scan
    → sudo ports free 2024
  exit 0
this branch --dry-run
  would stop ? (:8792)
  · skipped ? (:2024): …
  exit 0
this branch, only the root row:  skipped, exit 1 · --json → {"action": "skipped", "error": "…", "fix": "sudo ports free 2024"}

New tests:

  • TestStopAllSkipsUnowned: mixed rows, including a unit row and a docker-proxy row.
  • TestStopAllOnlyUnownedExitsOne.
  • TestStopAllExpectIgnoresSkipped.
  • TestStopAllSkippedJSON.

The existing TestStopAllExpectFailsClosed (the free path) still refuses an anonymous row.

Risk

Tier: risky (the kill path, --json, exit codes).

Can anything new be stopped? No. inspect.Stop already returned an error for every such row before signalling anything. Skipped rows never reach the stop call, and --expect stays all-or-nothing over the stoppable targets.

Public surface:

  • kill's exit code goes from 1 to 0 when the only "failures" were unstoppable rows.
  • --json gains the action value skipped. That's additive, and skipped results come after the others.
  • The stderr text for those rows changes.
  • kill --expect no longer refuses everything because of an unowned row.
  • inspect.unowned is exported as Unowned, with the same body.

Rollback: revert the squash commit. Nothing is persisted.

A fresh-context review said ok to ship, and confirmed nothing new can be stopped. Its three should-fixes are the second commit:

  • the --expect help and docs said "every target", which isn't true for kill any more;
  • an unowned docker-proxy got a sudo ports free hint that would fail again;
  • the exit-code table didn't list the all-skipped case.

Notes for the release

ports kill skips other users' listeners it can't stop, with the command that would, instead of failing the whole kill. In --json their action is skipped.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

kill: other users' pid-less rows flip the exit to 1

2 participants