Skip to content

feat(helper): overlay-based per-user game file overrides + systemd-run launching#5

Open
hikaps wants to merge 3 commits intodevelopfrom
fix/overlay-override
Open

feat(helper): overlay-based per-user game file overrides + systemd-run launching#5
hikaps wants to merge 3 commits intodevelopfrom
fix/overlay-override

Conversation

@hikaps
Copy link
Copy Markdown
Owner

@hikaps hikaps commented Apr 3, 2026

Summary

  • Systemd-run transient units: Replace machinectl shell + bash -c process spawning with systemd-run --unit couchplay-<user>.service for proper lifecycle management, automatic cleanup on crash, and Delegate=yes cgroup delegation
  • OverlayFS per-user game overrides: Mount per-user overlay filesystems at /run/couchplay/mounts/<user>/<gameId> so each split-screen player gets isolated save/config files without full game copies
  • Path safety hardening: Add startsWith(userHome) validation in CopyFileToUser, WriteFileToUser, CreateUserDirectory to constrain writes under user home directories; only chown directories that were actually created (not pre-existing ones)
  • Overlay mount resilience: Detect stale mounts via /proc/mounts on setup, auto-teardown; use direct nsenter -t 1 -m syscalls instead of shell mount/umount processes; lazy unmount fallback
  • Game path UI: Add FolderDialog at session profile level to select shared game directory for overlay mounts
  • Session model cleanup: Move overlayGamePath from per-instance (dead code) to session-level with real UI binding; remove unused borderless per-instance setting; default borderlessWindows to true

Test Plan

  • Build passes (cmake --build build)
  • All 13 tests pass (ctest --output-on-failure)
  • Manual: launch split-screen session with overlay patterns configured, verify per-user config isolation
  • Manual: kill helper mid-session, restart, verify stale mount cleanup works
  • Manual: test with Heroic Games Launcher flatpak preset

Breaking Changes

  • D-Bus LaunchInstance signature gains gamePath parameter (sssasssssasss)
  • io.github.hikaps.couchplay.run-as-user polkit action removed (superseded by systemd-run)
  • overlayGamePath, overlayEnabled, borderless removed from per-instance config (moved/deprecated)

@hikaps hikaps force-pushed the fix/overlay-override branch from 92c2705 to a4e0b42 Compare April 3, 2026 04:34
hikaps added 3 commits April 3, 2026 08:40
Implements kernel OverlayFS mounts to give each player instance their
own override files when sharing the same game installation on NTFS or
other shared filesystems.

Key changes:
- SystemOps: add mount/umount/umount2 via nsenter into PID 1 namespace
- CouchPlayHelper: SetupOverlayMount creates overlayfs with metacopy=on
  (upper/work on native Linux fs, lower on game path)
- CouchPlayHelper: LaunchInstance uses single dir-level BindPaths with
  PrivateMounts=no for propagation through flatpak/pressure-vessel
- CouchPlayHelper: TeardownOverlayMount with lazy umount fallback
- Disk-based overlay discovery (no in-memory state tracking)
- SessionRunner: setupOverlayMounts/teardownOverlayMounts orchestration
- QML: editable overlay game path in session setup
- 6 new tests covering mount, umount, lazy fallback, edge cases

This replaces all previous failed approaches (FLATPAK_BWRAP wrapper,
file-level bind mounts, global bind mounts) which don't survive
pressure-vessel's mount namespace isolation.
- Remove dead LD_PRELOAD interceptor logic from install-helper.sh
- Remove stale polkit action 'run-as-user' (machinectl era)
- Bake PrivateTmp=false and MountFlags=shared into service file
  (replaces external drop-in that was required at install time)
- Fix SetupOverlayMount: check /proc/mounts BEFORE cleaning workdir
  (prevents stale workdir data if previous mount was active)
- Fix /proc/mounts check: append space to prevent partial path match
- Fix SystemOps::umount2: properly map flags parameter instead of
  always hardcoding MNT_DETACH
- Fix misleading strerror(errno) after QProcess mount failure
  (QProcess doesn't set errno; use generic error message)
- Add QDir::cleanPath() to hashGamePath for path normalization
- Add stale workdir cleanup before overlay mount (overlayfs requires
  empty workdir)
- Use proper log categories in SessionRunner (qCWarning/qCDebug)
- Move getOverridesRootPath to private (no external callers)
… teardown

- Use QProcess::splitCommand() instead of naive space-split for
  gameCommand, properly handling quoted arguments in preset launch
  commands (e.g. paths with spaces)
- Replace stale strerror(errno) with mount point path in error
  messages after nsenter-based umount calls, since errno is
  meaningless after subprocess execution
- Fix mixed tab/space indentation in test mock
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.

1 participant