image: name: ps5-cachyos distribution: archlinux description: Arch + CachyOS extras — tty1 autologin, Gamescope + Steam, KDE Plasma (no SDDM) architecture: x86_64 source: downloader: archlinux-http url: https://geo.mirror.pkgbuild.com/iso skip_verification: true packages: manager: pacman # Do not "pacman -Su" the whole bootstrap: CachyOS *-v3 replaces glibc/pacman, breaks Docker/QEMU hooks and multilib. update: false cleanup: true repositories: - name: mirrorlist url: |- Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch sets: - packages: # Gamescope + Steam (Big Picture / gamepad UI) - gamescope - multilib/steam - mangohud - gamemode - multilib/lib32-mesa - multilib/lib32-vulkan-radeon - multilib/lib32-mangohud - xorg-xwayland - xorg-xinit # KDE Plasma (no SDDM — tty + dbus-run-session + startplasma-wayland). plasma-meta # pulls plasma-workspace, which ships /usr/bin/startplasma-{wayland,x11}; xorg-xinit # below provides startx for the optional `plasmax11` next-session token (X11 fallback). - plasma-meta - sddm - qt6-wayland - egl-wayland - konsole - dolphin # Audio / media - pipewire - wireplumber - pipewire-pulse # Display / GPU (AMD) — qualify extra/ so pacman does not prompt vs [cachyos] mesa - extra/mesa - extra/vulkan-radeon - extra/libva-mesa-driver - extra/xf86-video-amdgpu - libinput - xkeyboard-config # Networking - networkmanager - linux-firmware # GIO module libgiognutls.so (KDE/Konsole, GVfs, etc.): needs gnutls → nettle (libhogweed). # Explicit install avoids a sparse dependency tree under distrobuilder cleanup: true. - gnutls - nettle - glib-networking # System - base - openssh - sudo - nano - bash - mkinitcpio - kmod - e2fsprogs - cloud-utils - parted - polkit - dbus - kexec-tools - curl - dialog # Fonts (Steam UI + KDE) — CJK + emoji avoid "tofu" boxes in Steam Big Picture language list - ttf-dejavu - ttf-liberation - noto-fonts - noto-fonts-cjk - noto-fonts-emoji - fontconfig action: install files: - path: /etc/hostname generator: hostname - path: /etc/hosts generator: hosts - path: /etc/kernel/postinst.d/zz-update-boot generator: copy source: /tmp/build-staging/zz-update-boot mode: "0755" - path: /etc/fstab generator: copy source: /tmp/build-staging/fstab - path: /usr/local/sbin/grow-rootfs generator: copy source: /tmp/build-staging/files/grow-rootfs mode: "0755" - path: /etc/systemd/system/grow-rootfs.service generator: copy source: /tmp/build-staging/files/grow-rootfs.service - path: /opt/pkgs/ generator: copy source: /tmp/build-staging/pkgs - path: /usr/local/sbin/first-boot-setup generator: copy source: /tmp/build-staging/files/first-boot-setup mode: "0755" - path: /etc/systemd/system/first-boot.service generator: copy source: /tmp/build-staging/files/first-boot.service - path: /etc/profile.d/ps5-tty-session.sh generator: copy source: /tmp/build-staging/files/ps5-tty-session.sh mode: "0644" - path: /usr/bin/gamescope-session-ps5 generator: copy source: /tmp/build-staging/files/gamescope-session-ps5 mode: "0755" - path: /usr/bin/steamos-session-select generator: copy source: /tmp/build-staging/files/steamos-session-select mode: "0755" - path: /usr/share/applications/return-to-gaming-mode.desktop generator: copy source: /tmp/build-staging/files/return-to-gaming-mode.desktop - path: /usr/local/share/ps5-display.lua generator: copy source: /tmp/build-staging/files/ps5-display.lua - path: /usr/local/share/plasma-workspace-env-ps5.sh generator: copy source: /tmp/build-staging/files/plasma-workspace-env-ps5.sh mode: "0755" actions: - trigger: post-unpack action: |- #!/bin/bash set -eux # Pacman 7 Landlock sandbox is unsupported under QEMU; disable it. sed -i '/^\[options\]/a DisableSandbox' /etc/pacman.conf CACHYOS_PKG="https://mirror.cachyos.org/repo/x86_64/cachyos" pacman-key --init pacman-key --populate archlinux pacman-key --recv-keys F3B607488DB35A47 --keyserver keyserver.ubuntu.com pacman-key --lsign-key F3B607488DB35A47 # Keyring + main mirrorlist only (no *-v3 repos — those force a full distro migration in the chroot). pacman -U --noconfirm \ "${CACHYOS_PKG}/cachyos-keyring-20240331-1-any.pkg.tar.zst" \ "${CACHYOS_PKG}/cachyos-mirrorlist-27-1-any.pkg.tar.zst" # Optional CachyOS packages: repo listed *after* Arch so core/extra/multilib win on conflicts (mesa, steam deps). if ! grep -q '^\[cachyos\]' /etc/pacman.conf; then printf '\n[cachyos]\nInclude = /etc/pacman.d/cachyos-mirrorlist\n' >> /etc/pacman.conf fi # Enable #[multilib] / #Include block (\\\\ in YAML would break the sed address regex) sed -i '/^#\[multilib\]/,/^#Include/s/^#//' /etc/pacman.conf # Keep CI on a small stable mirror set. The full active global list can # select slow mirrors and fail pacman's low-speed download timeout. cat > /etc/pacman.d/mirrorlist <<'EOF' Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch EOF pacman -Syy --noconfirm - trigger: post-packages action: |- #!/bin/bash set -eux # fc-cache / systemctl can SIGSEGV under QEMU when image plat is linux/amd64 on arm64 hosts. fc-cache -f 2>/dev/null || true symlink_wants() { local src=$1 local target=$2 [ -e "$src" ] || return 0 local base base=$(basename "$src") mkdir -p "/etc/systemd/system/${target}.wants" ln -sf "$src" "/etc/systemd/system/${target}.wants/${base}" } sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config symlink_wants /usr/lib/systemd/system/sshd.service multi-user.target symlink_wants /usr/lib/systemd/system/NetworkManager.service multi-user.target # PipeWire/WirePlumber: user session after tty autologin; default.target matches Arch Sway image. for s in pipewire pipewire-pulse wireplumber; do symlink_wants "/usr/lib/systemd/system/${s}.service" default.target || true done - trigger: post-files action: |- #!/bin/bash set -eux mkdir -p /etc/systemd/system/local-fs.target.wants ln -sf /etc/systemd/system/grow-rootfs.service \ /etc/systemd/system/local-fs.target.wants/grow-rootfs.service # Stub out steamos-update so Steam's -steamos3 OOBE skips the SteamOS OTA # step cleanly. Exit 7 = "no update available" per Valve's convention. printf '#!/bin/bash\n# Stub: no SteamOS OTA on this image\nexit 7\n' \ > /usr/bin/steamos-update chmod +x /usr/bin/steamos-update useradd -m -G wheel,seat,video,audio,input -s /bin/bash steam echo "steam:steam" | chpasswd echo "%wheel ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/wheel # --- No SDDM: tty1 autologin + /etc/profile.d/ps5-tty-session.sh (+ ~/.bashrc source) --- # SDDM is only a display manager (login UI, VT handoff, relaunch). plasma-meta may # still pull sddm as a dependency; keep it masked. Remove leftover SDDM config from older images. rm -f /etc/sddm.conf.d/steamos.conf /etc/sddm.conf.d/zz-steamos-autologin.conf 2>/dev/null || true rm -f /etc/systemd/system/sddm.service.d/ps5-seat.conf 2>/dev/null || true rmdir /etc/systemd/system/sddm.service.d 2>/dev/null || true rm -f /usr/local/share/steam-bash_profile.ps5 2>/dev/null || true touch /etc/ps5-use-tty-sessions ln -sf /usr/lib/systemd/system/multi-user.target /etc/systemd/system/default.target ln -sf /dev/null /etc/systemd/system/sddm.service # First-boot wizard handles timezone/password/hostname; avoid duplicate prompts. ln -sf /dev/null /etc/systemd/system/systemd-firstboot.service mkdir -p /etc/systemd/system/getty@tty1.service.d printf '%s\n' '[Service]' 'ExecStart=' 'ExecStart=-/sbin/agetty --autologin steam --noclear %I $TERM' \ > /etc/systemd/system/getty@tty1.service.d/autologin.conf printf '%s\n' '[Unit]' 'After=first-boot.service' \ > /etc/systemd/system/getty@tty1.service.d/after-first-boot.conf mkdir -p /etc/systemd/system/multi-user.target.wants ln -sf /etc/systemd/system/first-boot.service \ /etc/systemd/system/multi-user.target.wants/first-boot.service # agetty --autologin often starts a non-login shell — ~/.bashrc must source profile.d. # Write via printf (not heredoc) to avoid column-0 lines that would terminate this # YAML block scalar. printf '%s\n' \ '# ps5-linux-image: tty1 autostart when /etc/profile was skipped (agetty autologin).' \ 'if [ -f /etc/profile.d/ps5-tty-session.sh ]; then' \ ' . /etc/profile.d/ps5-tty-session.sh' \ 'fi' \ > /home/steam/.bashrc chown steam:steam /home/steam/.bashrc chmod 644 /home/steam/.bashrc printf '%s\n' \ '# Login shells: /etc/profile sources profile.d first; keep .bashrc for interactive tools.' \ '[ -f ~/.bashrc ] && . ~/.bashrc' \ > /home/steam/.bash_profile chown steam:steam /home/steam/.bash_profile chmod 644 /home/steam/.bash_profile mkdir -p /home/steam/.config echo gamescope > /home/steam/.config/ps5-next-session # User PipeWire (systemd --user): post-packages symlinks system default.target, which does # not pull user units. Enable sockets/services under the steam user's default.target so # Plasma (real session bus) can connect to PipeWire. mkdir -p /home/steam/.config/systemd/user/default.target.wants for u in /usr/lib/systemd/user/pipewire.socket /usr/lib/systemd/user/pipewire-pulse.socket \ /usr/lib/systemd/user/wireplumber.service; do [ -e "$u" ] || continue ln -sf "$u" "/home/steam/.config/systemd/user/default.target.wants/$(basename "$u")" done chown -R steam:steam /home/steam/.config/systemd # Gamescope display profile: force sRGB colorimetry so gamescope does not set # BT2020_RGB on the DP connector. The PS5's internal DP->HDMI bridge cannot # correctly translate BT2020 signalling to HDMI, causing a black screen. # Staged via files: to /usr/local/share/ps5-display.lua to avoid heredoc # indentation conflicts with the YAML literal block scalar. mkdir -p /home/steam/.config/gamescope/scripts cp /usr/local/share/ps5-display.lua /home/steam/.config/gamescope/scripts/ps5-display.lua # Plasma (X11 from tty): avoid HDR negotiation that black-screens the PS5 DP→HDMI path. mkdir -p /home/steam/.config/plasma-workspace/env cp /usr/local/share/plasma-workspace-env-ps5.sh \ /home/steam/.config/plasma-workspace/env/ps5-drm-bridge.sh chmod +x /home/steam/.config/plasma-workspace/env/ps5-drm-bridge.sh # KDE Desktop shortcut: "Return to Gaming Mode" # chmod +x lets KDE trust and execute it without showing an "untrusted" dialog. mkdir -p /home/steam/Desktop cp /usr/share/applications/return-to-gaming-mode.desktop /home/steam/Desktop/ chmod +x /home/steam/Desktop/return-to-gaming-mode.desktop chown -R steam:steam /home/steam [ -f /etc/vconsole.conf ] || echo "KEYMAP=us" > /etc/vconsole.conf # Busybox-based initrd: polls for the root device (works after kexec, unlike # the systemd initrd which waits for udev events that never re-fire). # `kms` loads the amdgpu module + firmware early so the display comes up # before the rootfs is mounted. `keyboard` allows emergency-mode input. sed -i \ -e 's/^HOOKS=.*/HOOKS=(base udev modconf kms keyboard block filesystems fsck)/' \ -e 's/^MODULES=.*/MODULES=(amdgpu)/' \ /etc/mkinitcpio.conf if ls /opt/pkgs/*.pkg.tar.zst 1>/dev/null 2>&1; then pacman -U --noconfirm --ask 4 /opt/pkgs/*.pkg.tar.zst rm -rf /opt/pkgs KVER=$(ls -1t /lib/modules | head -1) mkinitcpio -k "$KVER" -g "/boot/initrd.img-$KVER" || true fi mkdir -p /boot/efi /etc/kernel/postinst.d/zz-update-boot mappings: architecture_map: archlinux