How mr-vaibh/park works
1. What this repo is
- park is a single Go CLI binary that temporarily freezes a process, frees its listening TCP port, and later restores the same process and port.
- The architecture is centered on one hard boundary: user-space CLI orchestration on top of OS-specific process/socket manipulation.
2. CLI entrypoint and command surface
- cmd/park/ is the user-facing layer: argument parsing, command dispatch, and terminal output.
- Main actions are park <port>, resume, release, list, plus auxiliary commands like ui, hold, sigcont, and upgrade.
- All commands funnel into shared internal subsystems rather than duplicating OS logic.
3. Port-to-process discovery
- internal/portfind/ locates the listening process and socket for a given TCP port.
- On Linux and macOS it uses platform-specific mechanisms to map a port to PID/fd, with parsers for kernel/network data in parse.go.
- This subsystem is the first step in the park flow: it identifies exactly which file descriptor must be closed inside the target process.
4. Process metadata and safety checks
- internal/procinfo/ gathers command-line, cwd, PID/start-time details, and implements the “should we touch this process?” checks.
- It enforces repo-level safety constraints such as refusing init-like processes, other users’ processes, and suspicious targets.
- This package also supports later resume by preserving enough identity information to recognize the original process.
5. State persistence
- internal/state/ stores parked-process metadata under ~/.park/<pid>.json.
- The saved state is the bridge between the two phases: park now, resume later.
- State is keyed by PID, with additional process identity data captured to reduce the risk of PID reuse issues.
6. Core injection engine
- internal/ptrace/ is the load-bearing subsystem that actually manipulates the target process and its sockets.
- The cross-platform interface in ptrace.go abstracts “attach, inject, restore, detach.”
- On Linux x86_64, ptrace_linux_amd64.go performs syscall injection to close the listening fd, and later recreate/bind/listen/dup2 it on resume.
7. Platform split and capability boundaries
- Linux support is split by architecture: full implementation on linux_amd64, stub/error paths for other Linux arches.
- macOS has its own path, including an arm64 implementation that uses Mach-based injection and thread control instead of Linux ptrace semantics.
- This split is important for architecture diagrams: the platform backend is not a detail; it is the core differentiator of behavior and support level.
8. Park lifecycle data flow
- park <port>: CLI → port discovery → safety checks → attach/inject close syscall → restore registers/bytes → detach/freeze → persist state.
- resume <port|pid>: CLI → load state → reattach → recreate listener fd and rebind it → restore process state → continue execution.
- release is the same state lookup path but skips re-binding the listener; it simply lets the process run again or terminates it if requested.
9. macOS-specific listener restoration
- The macOS path has extra behavior because listeners may be registered in kqueue-based event loops.
- On resume it may need to re-register the listener and restore non-blocking mode so async frameworks continue working.
- This is a platform-specific subflow inside the broader resume pipeline.
10. Operational model
- There is no daemon or background service; all state lives per-user in the filesystem.
- The tool relies on kernel privileges for attach/detach and on OS socket semantics to truly free the port.
- The repo is therefore a thin CLI over privileged kernel interactions, not a long-running control plane.
11. Tests and validation
- Unit tests cover parsing, state handling, sockaddr encoding, and related helper logic.
- A Linux integration test exercises the full end-to-end path: park a live server, bind another process to the freed port, then resume the original server.
- This mirrors the architecture: most logic is deterministic plumbing, while the critical integration boundary is kernel behavior.
12. Build and release flow
- The project is built and released as a Go binary with GitHub Actions and GoReleaser.
- The repo also includes install scripting and a docs site, but these are delivery channels rather than runtime subsystems.
- For an architecture diagram, these belong on the edge: build/release around the binary, not inside the runtime request path.
Main entry points: main.go park CLI · ptrace.go Ptrace core · procinfo.go Proc info · portfind.go Port find
Components 19
CLI
User-facing command surface and lifecycle commands
- park CLI · Command dispatch and terminal UX for park operations
cmd/park/main.go - UI · Interactive or status-oriented command surface
cmd/park/ui.go - Hold · Auxiliary command for keeping a process parked
cmd/park/hold.go - Sigcont · Auxiliary command for continuing a process
cmd/park/sigcont.go - Upgrade · Self-update or upgrade flow for the CLI binary
cmd/park/upgrade.go
Core
Shared discovery, safety, state, and injection subsystems
- Port find · Maps a listening TCP port to the owning process and socket
internal/portfind/portfind.go - Port parse · Parses OS network and kernel data for port lookup
internal/portfind/parse.go - Proc info · Collects process identity and enforces target safety checks
internal/procinfo/procinfo.go - Proc parse · Parses process metadata used for identity and validation
internal/procinfo/parse.go - State · Persists parked-process metadata under the user state directory
internal/state/state.go - Ptrace core · Attach, inject, restore, and detach abstraction
internal/ptrace/ptrace.go - Sockaddr · Socket address encoding and restoration helpers
internal/ptrace/sockaddr.go
Platform
OS and architecture-specific backends
- Linux amd64 · Syscall injection backend for Linux x86_64
internal/ptrace/ptrace_linux_amd64.go - Linux other · Unsupported Linux architecture path
internal/ptrace/ptrace_linux_other.go - macOS core · macOS injection and thread-control backend
internal/ptrace/ptrace_darwin.go - macOS arm64 · Mach-based arm64 implementation for macOS
internal/ptrace/ptrace_darwin_arm64.go
Connections 20
- park CLI → Port find: find port owner · Park starts by locating the listening process and socket
- park CLI → Proc info: validate target · Checks process identity and safety before touching it
- park CLI → Ptrace core: park/resume · Dispatches to the core injection lifecycle
- park CLI → State: persist state · Stores metadata needed for later resume or release
- UI → park CLI: drive flows · UI sits on the same command and lifecycle surface
- Hold → Proc info: inspect target · Auxiliary control path still depends on process identity
- Sigcont → Ptrace core: continue process · Uses the same process-control boundary to resume execution
- Upgrade → park CLI: replace binary · Upgrade is operationally adjacent to the main CLI
- Port find → Port parse: parse kernel data · Uses OS-specific parsing to map ports to processes
- Proc info → Proc parse: read metadata · Parses command line, cwd, pid, and start-time details
- park CLI → Port parse: platform lookup · Command flow depends on platform port discovery support
- Ptrace core → Sockaddr: encode addr · Restoration paths need socket address reconstruction
- Ptrace core → Linux amd64: linux amd64 · Full Linux x86_64 injection backend
- Ptrace core → Linux other: linux fallback · Unsupported Linux architectures return stubbed behavior
- Ptrace core → macOS core: darwin · macOS backend for attach and restore flows
- macOS core → macOS arm64: arm64 impl · Mach-based implementation on macOS arm64
- State → Proc info: identity match · Saved identity data helps avoid PID reuse mistakes
- CI → park CLI: validate binary · CI exercises command build and test paths
- Release → park CLI: ship binary · Release workflow packages the CLI for distribution
- Docs → park CLI: describe usage · Docs explain the runtime command surface