Add --clean-processes to remove stale session pid files

Scans the same $XDG_STATE_HOME/slocker-lite/run/ directory as
--list-processes and removes every pid file that's genuinely stale.
The liveness check and the removal happen atomically per file (the
same non-blocking flock() used to test it is held across the
remove() call itself), rather than reusing a separate earlier scan,
closing the race window where a new session could start in between.
Only files actually removed are reported, one line each; sessions
still running are left untouched and silently skipped.

Refactored list_sessions() and the new clean_stale_sessions() to
share a private open_session_file() helper for the open/read-pid/
recover-name step they both need.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
2026-08-22 09:16:57 +00:00
parent 8c55e5c288
commit d4c0e8f0a1
5 changed files with 157 additions and 42 deletions
+23 -8
View File
@@ -18,12 +18,18 @@ Source layout (all under `src/`):
- `main.cpp` — CLI entry point, dependency checks, orchestration (`mount_image()`,
`run_container()`, `cleanup_image()`, `unmount_image()`, `list_images_command()`,
`inspect_image_command()`, `create_volume_command()`, `list_volumes_command()`,
`delete_volume_command()`, `list_processes_command()`). `list_processes_command()`
implements `--list-processes` (long-option only): calls `list_sessions()`
(`pid_file.{h,cpp}`, see below) and prints one tab-aligned `pid`, `container
name`, `running`/`exited` row per entry (same two-column tab-alignment scheme
as `list_images_command()`/`list_volumes_command()`, extended to a third
column), no header row, silent success on an empty list.
`delete_volume_command()`, `list_processes_command()`, `clean_processes_command()`).
`list_processes_command()` implements `--list-processes` (long-option only):
calls `list_sessions()` (`pid_file.{h,cpp}`, see below) and prints one
tab-aligned `pid`, `container name`, `running`/`exited` row per entry (same
two-column tab-alignment scheme as `list_images_command()`/
`list_volumes_command()`, extended to a third column), no header row, silent
success on an empty list. `clean_processes_command()` implements
`--clean-processes` (also long-option only): calls `clean_stale_sessions()`
(`pid_file.{h,cpp}`) and prints one `removed stale pid file for '<name>' (pid
<pid>)` line per file actually removed — nothing is printed for sessions still
running, and an empty result (nothing stale) is silent success, same
convention as the rest of this file's list/delete commands.
`inspect_image_command()` implements `-i/--inspect
<image.tar>`: prints every `OciImageConfig` field (user/group, exposed ports, env,
volumes, default command) without mounting or running the image — extend it
@@ -206,7 +212,16 @@ Source layout (all under `src/`):
released again immediately either way, never left held by the check itself. A
file that can't be opened or doesn't parse as a pid (e.g. removed mid-scan) is
silently skipped, not reported as an error — scanning a live directory is
inherently racy.
inherently racy. Both `list_sessions()` and `clean_stale_sessions()` (the
latter implements `--clean-processes`) share a private `open_session_file()`
helper for the open/read-pid/recover-name step. `clean_stale_sessions()`
doesn't just remove whatever a separate `list_sessions()` call reported as not
running — it re-takes the same non-blocking `flock()` used to test liveness
and holds it across the `remove()` call itself, per file, so the stale check
and the removal stay atomic against a new session starting in the gap between
a check and a later removal. Only files it actually removes are reported back
(as `SessionInfo`s with `running=false`); still-locked (running) files are
left untouched and not reported.
- `config_file.{h,cpp}``load_config_file()` reads and parses (via libyaml's
document API, `<yaml.h>`) the `global` and `volumes` sections of the local YAML
config file located by `config_file_path()` (`$XDG_CONFIG_HOME/slocker-lite/config.yaml`,
@@ -285,7 +300,7 @@ Build directory is `buildDir/` (already configured).
full flag list: `-m/--mount`, `-r/--run`, `-u/--umount`, `-c/--cleanup`,
`-l/--list-images`, `-i/--inspect`, `-n/--no-nsenter`, `--user`, `--group`,
`--hostname`, `-v/--volume`, `--list-volumes`, `--delete-volume`,
`--delete-volume-full`, `--list-processes`, `-t/--test`, `--log-level`,
`--delete-volume-full`, `--list-processes`, `--clean-processes`, `-t/--test`, `--log-level`,
`-h/--help`, `-V/--version`)
- Run tests: `meson test -C buildDir`