# Conflicts: # packaging/arch/punktfunk-host.install # scripts/steamdeck/install.sh
149 lines
7.7 KiB
Plaintext
149 lines
7.7 KiB
Plaintext
# pacman install scriptlet — mirrors the RPM %post / deb postinst.
|
|
_ensure_update_group() {
|
|
# The (empty) opt-in group for web-console-triggered updates — nobody is auto-added.
|
|
getent group punktfunk-update >/dev/null 2>&1 || groupadd --system punktfunk-update 2>/dev/null || true
|
|
}
|
|
|
|
_ensure_punktfunk_group() {
|
|
# Owns the usbip vhci attach/detach nodes (60-punktfunk.rules). Separate from 'input' on
|
|
# purpose: writing 'attach' materialises an arbitrary emulated USB device, which is a root-only
|
|
# kernel primitive and must not ride on the group users are told to join for gamepads
|
|
# (security-review 2026-08-05 M-4).
|
|
getent group punktfunk >/dev/null 2>&1 || groupadd --system punktfunk 2>/dev/null || true
|
|
}
|
|
|
|
# CAP_SYS_NICE on the host binary — the GPU-scheduling grant.
|
|
#
|
|
# WHY: PyroWave encodes on the GPU's shader cores, so a GPU-bound game starves it (measured: the
|
|
# encode dispatch goes from ~2 ms to 15-18 ms at 95 % game load). The fix is an elevated
|
|
# global-priority Vulkan queue, which the driver gates on CAP_SYS_NICE — measured 2026-08-08 on an
|
|
# RTX 5070 Ti: WITHOUT the capability every priority class is refused, WITH it the encoder is
|
|
# granted REALTIME on the first attempt. RADV is the same. Without this line the knob exists and
|
|
# does nothing. Same capability, same mechanism, as our gamescope package sets on its own binary.
|
|
#
|
|
# NARROW: CAP_SYS_NICE only permits raising scheduling priority (nice/ioprio/affinity/RT class). It
|
|
# grants no filesystem, network or user-switching privilege, and it is NOT setuid.
|
|
#
|
|
# TWO CONSEQUENCES worth knowing before you debug something odd on this host:
|
|
# * a file capability makes the process AT_SECURE, so the dynamic loader IGNORES LD_LIBRARY_PATH
|
|
# and LD_PRELOAD for it. A library-path shim that used to work will silently stop.
|
|
# * core dumps are suppressed for capability-carrying binaries by default (fs.suid_dumpable).
|
|
#
|
|
# Never fails the install: a box without libcap, or a filesystem that cannot store capabilities
|
|
# (some overlay/NFS setups), just runs at default priority exactly as before.
|
|
_grant_sched_capability() {
|
|
setcap 'cap_sys_nice=ep' usr/bin/punktfunk-host 2>/dev/null || true
|
|
}
|
|
|
|
post_install() {
|
|
_ensure_update_group
|
|
_ensure_punktfunk_group
|
|
_grant_sched_capability
|
|
udevadm control --reload-rules 2>/dev/null || true
|
|
udevadm trigger --subsystem-match=misc 2>/dev/null || true
|
|
# Apply the UDP socket-buffer tuning now (also auto-applied at boot by systemd-sysctl).
|
|
sysctl -p /usr/lib/sysctl.d/99-punktfunk-net.conf >/dev/null 2>&1 || true
|
|
cat <<'MSG'
|
|
punktfunk-host installed.
|
|
1. Add yourself to the 'input' group for virtual gamepads:
|
|
sudo usermod -aG input "$USER" # then re-login
|
|
Only if you want the virtual Steam Deck pad (usbip), ALSO join 'punktfunk':
|
|
sudo usermod -aG punktfunk "$USER"
|
|
That group can emulate arbitrary USB devices — join it only on a machine you trust.
|
|
2. Pick a backend config (gamescope is the no-desktop default on SteamOS/Deck):
|
|
mkdir -p ~/.config/punktfunk
|
|
cp /usr/share/punktfunk/host.env.bazzite ~/.config/punktfunk/host.env
|
|
3. Enable the host:
|
|
systemctl --user enable --now punktfunk-host
|
|
|
|
NOTE: encode is NVENC-only. Install 'nvidia-utils' on an NVIDIA host. An AMD Steam Deck is NOT
|
|
yet supported — it needs a VAAPI (hevc_vaapi) encoder backend (see packaging/arch/README.md).
|
|
MSG
|
|
# Firewall: stock Arch ships none (ports already open); CachyOS ships ufw; some spins (EndeavourOS)
|
|
# enable firewalld. We install a ufw app profile AND firewalld service definitions but never touch
|
|
# the running firewall — just point the way for whichever is active.
|
|
if command -v ufw >/dev/null 2>&1; then
|
|
cat <<'MSG'
|
|
|
|
4. ufw is installed — open the streaming ports once (native-only host shown; add
|
|
'punktfunk-gamestream' as well for Moonlight compat):
|
|
sudo ufw allow punktfunk-native
|
|
MSG
|
|
fi
|
|
if command -v firewall-cmd >/dev/null 2>&1; then
|
|
cat <<'MSG'
|
|
|
|
4. firewalld is active — open the streaming ports once (native-only host shown; add
|
|
'punktfunk-gamestream' as well for Moonlight compat):
|
|
sudo firewall-cmd --reload # load the new service def
|
|
sudo firewall-cmd --permanent --add-service=punktfunk-native
|
|
sudo firewall-cmd --reload
|
|
MSG
|
|
fi
|
|
# Conflicting Moonlight-compatible host (Sunshine/Apollo/...): reuse the host's own detector so
|
|
# the warning lives in one place. Exit 1 = found; never fail the install on it.
|
|
if command -v punktfunk-host >/dev/null 2>&1; then
|
|
if ! conflict="$(punktfunk-host detect-conflicts 2>/dev/null)"; then
|
|
printf '\n%s\n' "$conflict"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
post_upgrade() {
|
|
_ensure_update_group
|
|
# Also on UPGRADE, not just post_install: 'punktfunk' was introduced in 0.25.0, so every box that
|
|
# reached it by `pacman -Syu` from 0.24.x ran only this function and never got the group at all —
|
|
# leaving 60-punktfunk.rules to chgrp to a nonexistent group, the vhci attach/detach nodes
|
|
# root-only, and the virtual Steam Deck pad silently unable to attach. groupadd is idempotent, so
|
|
# this is a no-op on boxes that installed fresh.
|
|
_ensure_punktfunk_group
|
|
# A replaced binary is a NEW inode — file capabilities do not survive the upgrade, so re-grant.
|
|
_grant_sched_capability
|
|
udevadm control --reload-rules 2>/dev/null || true
|
|
sysctl -p /usr/lib/sysctl.d/99-punktfunk-net.conf >/dev/null 2>&1 || true
|
|
_warn_stale_firewall_ports
|
|
}
|
|
|
|
# An already-open firewall does NOT pick up a port we added to a profile.
|
|
#
|
|
# ufw expands an app profile into concrete rules when you run `ufw allow`, and stores THOSE. Editing
|
|
# /etc/ufw/applications.d later — which is all a package upgrade does — changes nothing about the
|
|
# rules already installed. firewalld is friendlier (its permanent config names the service, so a
|
|
# reload re-reads the XML) but still needs that reload. Either way the operator has an old rule and
|
|
# no reason to suspect it.
|
|
#
|
|
# That is not hypothetical: 47993 (plugin UIs, a separate origin from the console) arrived exactly
|
|
# this way, and on an upgraded ufw box every plugin interface silently became an empty panel in the
|
|
# console. So on upgrade, look at what is actually open and say so — still without touching the
|
|
# running firewall, which stays the operator's call.
|
|
_warn_stale_firewall_ports() {
|
|
# `ufw status verbose` prints each rule with its EXPANDED ports — "47992/tcp (punktfunk-web)"
|
|
# before the refresh, "47992,47993/tcp (punktfunk-web)" after — so one listing answers both "is
|
|
# the profile allowed at all" and "does that rule know the new port". (Plain `ufw status` prints
|
|
# the profile NAME instead, which cannot tell the two apart.)
|
|
if command -v ufw >/dev/null 2>&1 &&
|
|
ufw status verbose 2>/dev/null | grep -q 'punktfunk-web' &&
|
|
! ufw status verbose 2>/dev/null | grep -q '47993'; then
|
|
cat <<'MSG'
|
|
|
|
punktfunk: your ufw rule for 'punktfunk-web' predates TCP 47993, the separate origin plugin UIs
|
|
are served from. Until it is refreshed, plugin interfaces will not load in the web console:
|
|
sudo ufw app update punktfunk-web && sudo ufw reload
|
|
MSG
|
|
fi
|
|
# `--info-service` asks the DAEMON, which answers from the definition it loaded at its last
|
|
# (re)start — precisely the stale copy we are warning about. The file on disk already says 47993.
|
|
if command -v firewall-cmd >/dev/null 2>&1 &&
|
|
firewall-cmd --state >/dev/null 2>&1 &&
|
|
firewall-cmd --query-service=punktfunk-web >/dev/null 2>&1 &&
|
|
! firewall-cmd --info-service=punktfunk-web 2>/dev/null | grep -q '47993'; then
|
|
cat <<'MSG'
|
|
|
|
punktfunk: the punktfunk-web firewalld service now also covers TCP 47993, the separate origin
|
|
plugin UIs are served from. Reload so the running firewall picks it up, or plugin interfaces will
|
|
not load in the web console:
|
|
sudo firewall-cmd --reload
|
|
MSG
|
|
fi
|
|
}
|