fix: detect mounts via /proc/self/mountinfo so stale FUSE works
Update PKGBUILD version / update-pkgver (push) Successful in 5s

mountinfo.Mounted lstats the path. When the sshfs link dies, every stat
on the mountpoint returns EIO, so -l filtered the dead mount out, mount
failed in MkdirAll, and -u failed before fusermount. Switch detection to
mountinfo.GetMounts (no stat) and add a fusermount -uz fallback so a
stale mount can actually be torn down.
This commit is contained in:
2026-05-04 10:08:13 +02:00
parent 8edddc5a28
commit e6a02e5bf7
3 changed files with 102 additions and 19 deletions
+40
View File
@@ -1,5 +1,45 @@
# Decisions
## 2026-05-04 Detect mounts via `/proc/self/mountinfo` instead of `stat`
- **Who**: Dom, ClaudeCode
- **Why**: `mountinfo.Mounted(path)` from `github.com/moby/sys/mountinfo` works
by `lstat`-ing the path. When a sshfs connection dies, the FUSE endpoint
stays in `/proc/mounts` but every `stat` on the mountpoint returns EIO.
All three sshfsc paths broke as a result:
- `-l` silently filtered the dead mount out (`Mounted` returned an error,
code skipped on `merr != nil`)
- mount path failed with `mkdir … file exists` because `MkdirAll` stats
before creating
- `-u` failed with `lstat … input/output error` before reaching
`fusermount`
Net effect: a stale mount was a dead end — couldn't be listed, couldn't be
unmounted, blocked re-mount.
- **Tradeoffs**:
- Switched mount detection to `mountinfo.GetMounts(SingleEntryFilter(path))`,
which parses `/proc/self/mountinfo` and never touches the path. Robust to
EIO on the mount target.
- `list_mounts` now uses `PrefixFilter(base)` and trims the base prefix.
Direct children only — nested mounts under an alias dir would be skipped
on purpose; sshfsc only manages one level.
- `verify_mount_dir` skips `MkdirAll` when the path is already a mountpoint.
Re-running `sshfsc <alias>` against a stale mount no longer errors on
mkdir; main's existing `is_mounted_at` check then prints "Already mounted"
and returns. The user can `sshfsc -u <alias>` to recover.
- `unmount_sshfs` falls back to `fusermount -uz` (lazy) when `-u` fails.
Lazy unmount detaches the FS from the tree immediately and lets dangling
refs settle later — exactly what stale FUSE needs. Plain `-u` first
keeps the clean path noise-free.
- **How**:
- New helper `is_mounted_at(path)`; replaces `mountinfo.Mounted` at every
call site (`main`, `verify_mount_dir`, `unmount_sshfs`).
- `list_mounts` rewritten around `PrefixFilter`. Trims `base + "/"` and
skips entries containing further separators.
- `run_fusermount(flag, mount)` extracted to keep `-u` and `-uz` calls
tidy. `unmount_sshfs` retries with `-uz` on first-call error.
- New tests: `TestIsMountedAtFalseOnPlainDir`,
`TestIsMountedAtFalseOnMissingPath`. Existing tests stay green —
`mountinfo.GetMounts` returns empty under the test tmpdirs.
## 2026-05-04 Add `-l` (list) and `-u` (unmount) flags
- **Who**: Dom, ClaudeCode
- **Why**: Mounts under `$XDG_RUNTIME_DIR/sshfs/<alias>` had to be listed and