Field report, Nobara + 0.20.0: switching into Game Mode mid-stream disconnects the client and the box never lights up again. His journal has the whole mechanism, ten seconds apart: 12:34:18.9 freed Steam: stopped the display manager for this stream 12:34:29.0 systemd[1685]: Stopping punktfunk-host.service Stopping the display manager ends the user's last login session. The packaged host is a `systemd --user` unit, so logind then stops user@1000.service once UserStopDelaySec elapses — 10s by default on Nobara — and takes the host with it. The stream dies, the scheduled restore never runs, and the display manager stays down with nothing left to restart it: a black box that needs a VT to recover. Exactly the two symptoms reported, and the intermittency is just whether an active Gaming Mode session was there to trigger the takeover at all. It never showed on the repro VM because lingering was enabled there for the earlier sessionless tests (`Linger=yes` — confirmed on the VM today), which is precisely the thing that breaks the dependency: logind keeps the user manager alive with no session. Our KDE/GNOME/Arch setup guides already ask for it; his box, following the KDE route, did not have it. So the takeover now ensures lingering BEFORE it touches the display manager: `loginctl enable-linger` directly (allow_active in logind's own policy — verified working unprivileged on Nobara), else the packaged helper gains a `linger` verb that enables it for PKEXEC_UID alone, never a caller-named user. If neither works the takeover is refused with an actionable error and managed degrades to attach — mirroring the box's own session is strictly better than a screen that needs a VT. Hosts that cannot be reached this way (root, a system unit) skip the check: the cgroup test is a pure `cgroup_under_user_manager` with a unit test, matched against the real shapes on a Nobara box (`user@1000.service/app.slice/...` vs a `session-N.scope`). Also documents the requirement in the gamescope guide's Nobara section. Checked on Linux: clippy -D warnings, 78 tests, rustfmt; helper verified with `sh -n`, and the linger enable/disable round-trip run live on the Nobara VM.
56 lines
2.3 KiB
Bash
56 lines
2.3 KiB
Bash
#!/bin/sh
|
|
# Privileged display-manager verbs for the punktfunk managed gamescope takeover.
|
|
#
|
|
# On DM-autologin boxes whose display manager does not survive a masked session unit (Nobara's
|
|
# plasmalogin, unknown DMs), taking the Gaming Mode session over means stopping the display
|
|
# manager for the length of the stream and restarting it afterwards — root-only operations. The
|
|
# host invokes this helper via pkexec under its own polkit action
|
|
# (io.unom.punktfunk.dm-helper.policy, installed by the packages), the same mechanism these
|
|
# distros use for their own session switching (Nobara's os-session-select).
|
|
#
|
|
# The unit is NEVER caller-controlled: it is derived here from the display-manager.service alias
|
|
# symlink, so the polkit grant's blast radius is exactly "the box's own display manager" — a
|
|
# local-seat operation, not arbitrary unit management.
|
|
set -eu
|
|
|
|
dm_unit() {
|
|
target=$(readlink /etc/systemd/system/display-manager.service) || {
|
|
echo "pf-dm-helper: no display-manager.service alias — no display manager to manage" >&2
|
|
exit 1
|
|
}
|
|
basename "$target"
|
|
}
|
|
|
|
case "${1-}" in
|
|
stop)
|
|
exec systemctl stop "$(dm_unit)"
|
|
;;
|
|
restore)
|
|
dm=$(dm_unit)
|
|
# reset-failed first: a relogin loop may have tripped the unit's start limit, and a plain
|
|
# restart would be refused until the accounting is cleared.
|
|
systemctl reset-failed "$dm" 2>/dev/null || :
|
|
exec systemctl restart "$dm"
|
|
;;
|
|
linger)
|
|
# Keep the caller's own `systemd --user` manager alive across the stop. Stopping the display
|
|
# manager ends the user's last login session, and logind then stops user@<uid>.service after
|
|
# UserStopDelaySec (10s by default) — which takes the host that asked for the takeover with
|
|
# it, so nothing is left to restart the display manager and the box stays dark. Lingering is
|
|
# what breaks that dependency (the setup docs already ask for it).
|
|
#
|
|
# The user is NEVER caller-named: PKEXEC_UID is set by pkexec from the authenticated caller,
|
|
# so this grant enables lingering for that caller alone.
|
|
uid=${PKEXEC_UID:-}
|
|
[ -n "$uid" ] || {
|
|
echo "pf-dm-helper: no PKEXEC_UID in the environment — refusing to guess a user" >&2
|
|
exit 1
|
|
}
|
|
exec loginctl enable-linger "$uid"
|
|
;;
|
|
*)
|
|
echo "usage: pf-dm-helper stop|restore|linger" >&2
|
|
exit 2
|
|
;;
|
|
esac
|