review pass: mount safety, abort/quit robustness, UI fixes

Engine / safety:
- verify mount points against /proc/self/mountinfo instead of path
  existence; refuse to sync into a leftover (unmounted) directory that
  would otherwise receive the library on the root filesystem
- resolve udisks block devices by label when the path is not mounted,
  and never let findmnt fall back to the containing root filesystem
- abort now SIGTERMs the whole child process group (sh -c/podkit and
  rsync children included), escalating to SIGKILL after 2s
- quitting while a sync runs aborts and waits for the engine instead of
  orphaning the child
- atomically mark the engine busy before spawning to prevent double
  syncs; persist state before publishing completion
- don't follow symlinked directories while scanning (recursion loops)
- prune empty directories recursively when removing stale files

UI:
- help overlay was clipped (hardcoded height): size it from content
- speed/ETA were pushed onto a line the progress panel clipped; show
  them right-aligned on the bytes row
- leaving log follow with u/d now scrolls from the bottom instead of
  jumping to the top of the log
- reload config with r (label updated), refresh mounts on completion so
  last-sync ages are current
- fix width underflows on narrow terminals; terminal-aware sidebar
  scrolling

Tests: mountinfo unescape, process-group abort, and a TestBackend render
smoke test covering all tabs, small terminals and the help overlay.
This commit is contained in:
Sebastian
2026-09-10 19:35:03 +02:00
parent 5b1e8b742b
commit f566162c29
11 changed files with 470 additions and 138 deletions
+11 -2
View File
@@ -19,7 +19,11 @@ living dashboard instead of a batch CLI.
- **Live sync engine** — streams `rclone` and `rsync` output, parses progress
(byte-weighted via `--info=progress2`), NFC-aware diffing for
macOS→FAT32/Android devices, optional `fatsort` finalize for Mlove devices.
- **Abort-safe** — `a` kills the running child process cleanly.
- **Abort-safe** — `a` kills the running child process group cleanly; quitting
while a sync runs aborts it first instead of leaving it orphaned.
- **Mount-aware** — a path that exists but is not a real mount point is flagged
and refused as a sync target, so a leftover mount directory can't silently
receive a sync on the root filesystem.
- Reads the existing `~/.config/dap-sync/config.toml` (compatible with
`dap-sync`), persists last-sync state to `~/.local/share/dap-sync/sync-state.toml`.
@@ -41,7 +45,7 @@ cargo build --release
| `a` | abort running sync |
| `m` | mount / unmount device (udisks2, no sudo) |
| `Tab` / `1-3`| switch tab |
| `r` | refresh device mounts |
| `r` | reload config + refresh mounts |
| `f` | toggle log follow |
| `u` / `d` | scroll logs |
| `x` | clear logs |
@@ -91,6 +95,11 @@ Devices are mounted/unmounted without sudo via **udisks2**:
mounts the target first (resolved by mount-point label via `lsblk`). Only the
mlove `fatsort` step needs root (raw block device).
Mount status and sync targets are validated against the kernel mount table
(`/proc/self/mountinfo`), not just directory existence: if the configured
`mount_point` exists but is not actually mounted, `dap-tui` refuses to sync to
it rather than writing the library onto the root filesystem.
## Development
```bash