From 48d795da542c377ae3fb7988f0edfff6c79c89b7 Mon Sep 17 00:00:00 2001 From: Breadway Date: Sun, 16 Aug 2026 00:54:40 +0800 Subject: [PATCH] iso: add bos-nvidia-setup for optional proprietary NVIDIA Click-to-install path for machines first-boot already offers. Installs nvidia + nvidia-utils (never cuda), writes ~/.config/hypr/nvidia.lua, and hyprland.lua dofiles that file only if it exists. Mesa stays unchanged. Not on the ISO. Reboot after. --- docs/hardware.md | 15 +- .../etc/skel/.config/hypr/hyprland.lua | 11 ++ iso/airootfs/usr/local/bin/bos-nvidia-setup | 150 ++++++++++++++++++ iso/profiledef.sh | 1 + scripts/ci-verify-bake.sh | 11 ++ scripts/smoke-test.sh | 9 ++ 6 files changed, 193 insertions(+), 4 deletions(-) create mode 100755 iso/airootfs/usr/local/bin/bos-nvidia-setup diff --git a/docs/hardware.md b/docs/hardware.md index 2f87838..20c333b 100644 --- a/docs/hardware.md +++ b/docs/hardware.md @@ -4,14 +4,21 @@ BOS ships the generic **Mesa** stack. AMD and Intel work out of the box. -**NVIDIA is unsupported.** The proprietary driver is not included, NVIDIA -firmware is not on the image, and there is no Hyprland NVIDIA env wiring. -Installing `nvidia` / `nvidia-utils` after the fact is not a product path. +The proprietary NVIDIA driver is **not on the ISO**. NVIDIA firmware is +not on the image either (`linux-firmware-nvidia` stays commented out in +`packages.x86_64`). Default Hyprland env is vendor-neutral. On first graphical login, `bos-first-boot` probes `lspci` / `/proc` and, if an NVIDIA GPU is present, writes `~/.local/state/bos/nvidia-offer.json` and notifies that the proprietary driver is not on the ISO. It does **not** -install anything. bos-settings can grow a panel that reads that file later. +install anything. + +The optional proprietary path is `bos-nvidia-setup` or the Settings → +Updates NVIDIA button. That installs `nvidia` + `nvidia-utils` (never +cuda) and writes `~/.config/hypr/nvidia.lua`. `hyprland.lua` dofiles that +drop-in **only if the file exists**, so Mesa machines stay unchanged. +Reboot after. Installing the packages by hand without the drop-in is not +enough for a working Hyprland session. The same probe leaves a HiDPI hint at `~/.local/state/bos/hidpi-hint.json` when scale > 1 or the panel is dense; it never rewrites `monitors.json`. diff --git a/iso/airootfs/etc/skel/.config/hypr/hyprland.lua b/iso/airootfs/etc/skel/.config/hypr/hyprland.lua index d16a363..565da5b 100644 --- a/iso/airootfs/etc/skel/.config/hypr/hyprland.lua +++ b/iso/airootfs/etc/skel/.config/hypr/hyprland.lua @@ -77,6 +77,17 @@ hl.env("SDL_VIDEODRIVER", "wayland") hl.env("ELECTRON_OZONE_PLATFORM_HINT", "auto") hl.env("_JAVA_AWT_WM_NONREPARENTING", "1") +-- Optional NVIDIA env from bos-nvidia-setup. Mesa machines have no file. +-- bos-nvidia-setup: optional proprietary env; no-op when the file is absent +do + local nvidia = (os.getenv("HOME") or "") .. "/.config/hypr/nvidia.lua" + local f = io.open(nvidia, "r") + if f then + f:close() + pcall(dofile, nvidia) + end +end + -- kitty sets its own background_opacity (see kitty.conf), so the global blur -- above blurs behind the terminal while keeping text fully opaque. diff --git a/iso/airootfs/usr/local/bin/bos-nvidia-setup b/iso/airootfs/usr/local/bin/bos-nvidia-setup new file mode 100755 index 0000000..d287f53 --- /dev/null +++ b/iso/airootfs/usr/local/bin/bos-nvidia-setup @@ -0,0 +1,150 @@ +#!/bin/bash +# bos-nvidia-setup — optional proprietary NVIDIA driver + Hyprland env. +# +# Installs nvidia + nvidia-utils only (never cuda). Writes +# ~/.config/hypr/nvidia.lua, which skel hyprland.lua dofiles only when +# the file exists — Mesa machines stay unchanged. Existing installs get +# the same include patched in if it is missing. +# +# Click-to-install from Settings, or run by hand. Not invoked from +# bos-first-boot. Idempotent. Prints "reboot required". +# +# Must run on an installed system. Elevates via pkexec, then sudo. +set -uo pipefail + +usage() { + cat <<'EOF' +Usage: bos-nvidia-setup [--home DIR] + +Install nvidia + nvidia-utils (not cuda) and write the Hyprland NVIDIA +env drop-in for this user. Reboot after. + + --home DIR user home that owns ~/.config/hypr (required under pkexec + if PKEXEC_UID / SUDO_USER cannot be resolved) +EOF +} + +TARGET_HOME="" +while [[ $# -gt 0 ]]; do + case "$1" in + --home) + TARGET_HOME="${2:-}" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "bos-nvidia-setup: unknown argument: $1" >&2 + usage >&2 + exit 2 + ;; + esac +done + +if [[ "$(id -un)" == "liveuser" || -d /run/archiso ]]; then + echo "bos-nvidia-setup is for an installed system, not the live ISO." >&2 + exit 1 +fi + +if [[ "$(id -u)" -ne 0 ]]; then + home="${TARGET_HOME:-${HOME:-}}" + if [[ -z "$home" ]]; then + echo "bos-nvidia-setup: cannot determine home; pass --home" >&2 + exit 1 + fi + self="$(command -v bos-nvidia-setup 2>/dev/null || true)" + [[ -n "$self" ]] || self="$(readlink -f "$0" 2>/dev/null || printf '%s' "$0")" + if command -v pkexec >/dev/null 2>&1; then + exec pkexec "$self" --home "$home" + fi + if command -v sudo >/dev/null 2>&1; then + exec sudo "$self" --home "$home" + fi + echo "bos-nvidia-setup: need root (pkexec or sudo)" >&2 + exit 1 +fi + +if [[ -z "$TARGET_HOME" ]]; then + if [[ -n "${PKEXEC_UID:-}" ]]; then + TARGET_HOME="$(getent passwd "$PKEXEC_UID" | cut -d: -f6 || true)" + elif [[ -n "${SUDO_USER:-}" && "${SUDO_USER}" != root ]]; then + TARGET_HOME="$(getent passwd "$SUDO_USER" | cut -d: -f6 || true)" + fi +fi + +if [[ -z "$TARGET_HOME" || "$TARGET_HOME" == /root || ! -d "$TARGET_HOME" ]]; then + echo "bos-nvidia-setup: cannot determine user home (pass --home)" >&2 + exit 1 +fi + +HYPR_DIR="$TARGET_HOME/.config/hypr" +NVIDIA_LUA="$HYPR_DIR/nvidia.lua" +HYPR_LUA="$HYPR_DIR/hyprland.lua" + +# Hyprland 0.56 (Aquamarine). Wiki (https://wiki.hypr.land/Nvidia/): +# LIBVA_DRIVER_NAME + __GLX_VENDOR_LIBRARY_NAME. NVD_BACKEND is the +# current VA-API hint. No WLR_* (not wlroots). No GBM_BACKEND (not +# required; older docs cargo-culted it and it can break Firefox). +NVIDIA_LUA_BODY='-- Written by bos-nvidia-setup. hyprland.lua dofiles this only when it exists. +-- Hyprland 0.56 (Aquamarine) — no WLR_* variables. +-- https://wiki.hypr.land/Nvidia/ +hl.env("LIBVA_DRIVER_NAME", "nvidia") +hl.env("__GLX_VENDOR_LIBRARY_NAME", "nvidia") +hl.env("NVD_BACKEND", "direct") +' + +# Self-contained so it is safe to append to a hand-edited hyprland.lua. +HYPR_INCLUDE='-- bos-nvidia-setup: optional proprietary env; no-op when the file is absent +do + local nvidia = (os.getenv("HOME") or "") .. "/.config/hypr/nvidia.lua" + local f = io.open(nvidia, "r") + if f then + f:close() + pcall(dofile, nvidia) + end +end +' + +own_as_user() { + local path="$1" + [[ -e "$path" ]] || return 0 + local owner + owner="$(stat -c '%u:%g' "$TARGET_HOME" 2>/dev/null || true)" + [[ -n "$owner" ]] || return 0 + chown "$owner" "$path" 2>/dev/null || true +} + +echo "==> Installing nvidia + nvidia-utils (not cuda)" +if ! command -v pacman >/dev/null 2>&1; then + echo "bos-nvidia-setup: pacman not found" >&2 + exit 1 +fi +if ! pacman -S --needed --noconfirm -- nvidia nvidia-utils; then + echo "bos-nvidia-setup: pacman install failed" >&2 + exit 1 +fi + +echo "==> Writing $NVIDIA_LUA" +mkdir -p "$HYPR_DIR" || { + echo "bos-nvidia-setup: cannot create $HYPR_DIR" >&2 + exit 1 +} +printf '%s' "$NVIDIA_LUA_BODY" >"$NVIDIA_LUA" || { + echo "bos-nvidia-setup: cannot write $NVIDIA_LUA" >&2 + exit 1 +} +own_as_user "$NVIDIA_LUA" + +if [[ -f "$HYPR_LUA" ]] && ! grep -q 'nvidia\.lua' "$HYPR_LUA"; then + echo "==> Including nvidia.lua from $HYPR_LUA" + if [[ -n "$(tail -c1 "$HYPR_LUA" 2>/dev/null || true)" ]]; then + printf '\n' >>"$HYPR_LUA" + fi + printf '%s\n' "$HYPR_INCLUDE" >>"$HYPR_LUA" + own_as_user "$HYPR_LUA" +fi + +echo "reboot required" +exit 0 diff --git a/iso/profiledef.sh b/iso/profiledef.sh index f52295b..462f74e 100644 --- a/iso/profiledef.sh +++ b/iso/profiledef.sh @@ -31,5 +31,6 @@ file_permissions=( ["/usr/local/bin/bos-update"]="0:0:755" ["/usr/local/bin/bos-rescue"]="0:0:755" ["/usr/local/bin/bos-first-boot"]="0:0:755" + ["/usr/local/bin/bos-nvidia-setup"]="0:0:755" ["/usr/local/bin/bos-enable-bakery-user-units"]="0:0:755" ) diff --git a/scripts/ci-verify-bake.sh b/scripts/ci-verify-bake.sh index 68e357d..e55b11e 100755 --- a/scripts/ci-verify-bake.sh +++ b/scripts/ci-verify-bake.sh @@ -47,6 +47,11 @@ PY echo "== lockfile $LOCKFILE ==" echo " ${#REQUIRED_BINS[@]} required, ${#OPTIONAL_BINS[@]} optional" +if grep -qE '^nvidia(-utils|-dkms|-open)?$' "$REPO/iso/packages.x86_64"; then + bad "iso/packages.x86_64 lists an nvidia driver package" +else + ok "iso/packages.x86_64 has no nvidia driver package" +fi echo "== host tools ==" if command -v grub-install >/dev/null 2>&1; then ok "grub-install (uefi.grub bootmode)" @@ -140,6 +145,7 @@ if [[ -n "$AIROOTFS" || -n "$SKEL" ]]; then for b in "${REQUIRED_BINS[@]}"; do check_exec "$AIROOTFS/usr/local/bin/$b" "image required bin $b" done + check_exec "$AIROOTFS/usr/local/bin/bos-nvidia-setup" "image bos-nvidia-setup" check_dir "$AIROOTFS/usr/local/share/breadhelp/content" "image breadhelp content" fi if [[ -n "$SKEL" ]]; then @@ -152,6 +158,11 @@ if [[ -n "$AIROOTFS" || -n "$SKEL" ]]; then fi done check_file "$SKEL/.config/hypr/hyprland.lua" "skel hyprland.lua" + if grep -q 'nvidia.lua' "$SKEL/.config/hypr/hyprland.lua"; then + ok "skel hyprland.lua includes nvidia.lua only if present" + else + bad "skel hyprland.lua does not mention nvidia.lua" + fi fi image_units_json="" if [[ -n "$SKEL" && -f "$SKEL/.local/state/bakery/installed.json" ]]; then diff --git a/scripts/smoke-test.sh b/scripts/smoke-test.sh index 81bad6a..ccdc571 100755 --- a/scripts/smoke-test.sh +++ b/scripts/smoke-test.sh @@ -67,6 +67,13 @@ check "breadhelp content installed" \ check "bos-netcheck present" "command -v bos-netcheck" check "bos-rescue present" "command -v bos-rescue" check "bos-first-boot present" "command -v bos-first-boot" +check "bos-nvidia-setup present" "command -v bos-nvidia-setup" +if pacman -Qq nvidia >/dev/null 2>&1; then + note "nvidia installed (optional proprietary path)" + check "nvidia env drop-in present" "[ -f \"\$HOME/.config/hypr/nvidia.lua\" ]" +else + check "nvidia not on the default image" "! pacman -Qq nvidia" +fi echo "== bakery user units (global enable) ==" # A later useradd does not enable --user units unless they were enabled @@ -98,6 +105,8 @@ check "useradd SKEL is /etc/skel" \ echo "== default dotfiles ==" check "hyprland.lua present" "[ -f \"\$HOME/.config/hypr/hyprland.lua\" ]" +check "hyprland.lua includes nvidia.lua only if present" \ + "grep -q 'nvidia.lua' \"\$HOME/.config/hypr/hyprland.lua\"" check "binds.json present" "[ -f \"\$HOME/.config/hypr/binds.json\" ]" check "monitors.json present" "[ -f \"\$HOME/.config/hypr/monitors.json\" ]" check "settings.json present" "[ -f \"\$HOME/.config/hypr/settings.json\" ]"