#!/usr/bin/env bash # Preflight: catch problems before we install anything. # Fail fast and loud, with remediation hints. preflight_all() { preflight_session preflight_remote_session preflight_gpu preflight_kms_modeset preflight_audio preflight_headless } preflight_session() { if [[ "${SESSION_TYPE:-}" != "wayland" ]]; then warn "Session type '$SESSION_TYPE' — KMS capture works at the DRM level so it can still succeed," warn "but this installer's defaults assume Hyprland on Wayland." else ok "Wayland session detected" fi } preflight_remote_session() { # Sunshine's user service needs the local Wayland session to be reachable. # If we're over pure SSH (no forwarded DBUS / WAYLAND_DISPLAY), the service start # at the end of the install will fail. Warn now so the user knows. if [[ -n "${SSH_CONNECTION:-}" && -z "${WAYLAND_DISPLAY:-}" && -z "${DISPLAY:-}" ]]; then warn "Running over SSH without a graphical session. Packages will install," warn "but the systemd --user service will only come up cleanly once you log in" warn "to Hyprland on the console. That's fine — just log in afterwards." fi } preflight_gpu() { case "$GPU_VENDOR" in nvidia) if ! command -v nvidia-smi >/dev/null 2>&1; then warn "nvidia-smi not found yet — nvidia-utils will be installed shortly." return 0 fi if ! nvidia-smi -L >/dev/null 2>&1; then err "nvidia-smi exists but can't talk to the driver. Driver not loaded?" err "Check: 'lsmod | grep nvidia' and 'dmesg | grep -i nvidia'" exit 1 fi ok "NVIDIA driver responsive ($(nvidia-smi -L | head -n1))" ;; amd) if ! lsmod | grep -q '^amdgpu'; then warn "amdgpu kernel module not loaded. Hardware encode (VAAPI) will likely fail until it is." else ok "amdgpu kernel module loaded" fi ;; intel) ok "Intel GPU — will install intel-media-driver" ;; esac } preflight_kms_modeset() { # KMS capture needs nvidia-drm.modeset=1 on NVIDIA. Driver 560+ defaults to 1, # but if the user is on something older or has explicitly set 0, capture will fail. [[ "$GPU_VENDOR" == "nvidia" ]] || return 0 # Cmdline check is read-only and reliable when explicitly set. if grep -q 'nvidia-drm.modeset=1' /proc/cmdline; then ok "nvidia-drm.modeset=1 set on kernel cmdline" return 0 fi if grep -q 'nvidia-drm.modeset=0' /proc/cmdline; then err "nvidia-drm.modeset=0 is set on the kernel cmdline. KMS capture WILL fail." err "Remove it (e.g., from /boot/loader/entries/*.conf or /etc/kernel/cmdline + reinstall-kernels)" err "and reboot before running this installer." exit 1 fi # Not on cmdline — check the runtime parameter. On 560+ this defaults to Y. # /sys file is root-readable; modinfo gives the default without sudo. local default="" if command -v modinfo >/dev/null 2>&1; then default="$(modinfo -F parm nvidia_drm 2>/dev/null | awk -F: '/^modeset:/ {print $2}' | head -n1 || true)" fi if [[ -n "$default" ]]; then info "nvidia_drm modeset default per modinfo: ${default## }" fi warn "nvidia-drm.modeset=1 not explicitly set on cmdline." warn "Modern drivers (≥560) default to enabled, so this is usually fine — but if KMS" warn "capture fails after install, add 'nvidia-drm.modeset=1' to your kernel cmdline." } preflight_audio() { # Sunshine captures audio via the PulseAudio API; on Omarchy that's pipewire-pulse. if pkg_installed pipewire-pulse; then ok "pipewire-pulse present (audio capture path OK)" else warn "pipewire-pulse is not installed. Audio capture may not work until it is." fi } preflight_headless() { # Only relevant in headless mode. Checks are non-fatal: install can proceed # even if Hyprland isn't reachable right now (hooks just won't function until # the user logs into Hyprland on the host). [[ "${STREAM_MODE:-}" == "headless" ]] || return 0 if command -v hyprctl >/dev/null 2>&1; then ok "hyprctl on PATH" else warn "hyprctl not found. Headless prep-cmd hooks will fail until Hyprland is installed and reachable." fi if pkg_installed jq; then ok "jq installed (prep-cmd hooks have their parser)" else info "jq not installed yet — will be installed in the packages step." fi if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then ok "Hyprland instance signature present in environment" else local rt="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" if compgen -G "$rt/hypr/*/" >/dev/null 2>&1; then ok "Hyprland runtime directory found under $rt/hypr/" else warn "Hyprland does not appear to be running. Install will proceed; hooks will only work once you log into Hyprland on the host." fi fi }