#!/usr/bin/env bash # The parts of an install that depend on what the machine actually is: the # NVIDIA driver, the machine owner key that lets it load under Secure Boot, # Fedora's preinstalled extras, and firmware. # # Runs last. MOK enrollment arms a prompt consumed at the next boot and firmware # updates can ask for a reboot, so neither belongs in front of the package work # or the dotfiles -- a machine that reboots out of this stage has already been # fully configured. # # Nothing here decides anything. Every branch is an answer the interview # collected before the run began, and an absent answer means no, which is what # makes this safe to re-run by hand while repairing one piece of a machine. # # sunhat's version of this opened an editor in the middle of the run so grub # could be hand-corrected. That is the exact failure this repository exists to # avoid, and it is unnecessary: grubby replaces an argument that already exists # rather than appending a second copy, so the duplicates that had to be cleaned # up by hand cannot accumulate in the first place. set -uo pipefail log() { echo -e "\033[1;34m[INFO]\033[0m $*"; } warn() { echo -e "\033[1;33m[WARN]\033[0m $*" >&2; } # Fedora ships these and Panama uses none of them. Named here rather than in the # interview so there is one list: the interview asks for it with --debloat-list # to name what it is about to remove, and this stage removes it. A package that # is not installed is skipped rather than passed to dnf, so the list can outlive # a Fedora release -- totem left in Fedora 43 and the list should not start # failing because of it. DEBLOAT=(gnome-contacts gnome-tour gnome-maps showtime) if [[ "${1:-}" == "--debloat-list" ]]; then printf '%s\n' "${DEBLOAT[@]}" exit 0 fi # ── NVIDIA ─────────────────────────────────────────────────────────────────── if [[ "${PANAMA_NVIDIA:-no}" == yes ]]; then # The interview asks about MOK enrollment only when mokutil was present to # see Secure Boot at all. Re-check here rather than trusting that the # question was ever asked: installing akmod-nvidia and blacklisting # nouveau under Secure Boot with no key to enroll produces a machine that # reboots into an unloadable driver with its fallback disabled -- the one # failure in this installer that costs a person their display. if mokutil --sb-state 2>/dev/null | grep -qi 'secureboot enabled' \ && [[ -z "${PANAMA_MOK_HASH:-}" ]]; then warn "Secure Boot is on and no MOK enrollment was prepared; refusing to install" warn "the NVIDIA driver, which could not load. Re-run ./install and answer the" warn "Secure Boot question, or disable Secure Boot first." else log "Installing the NVIDIA driver" if sudo dnf install -y akmod-nvidia xorg-x11-drv-nvidia-cuda; then # nouveau has to be out of the way before the kernel would otherwise # bind it, which is why these are kernel arguments and not a modprobe # drop-in. modeset=1 is what makes the Wayland session work at all. if command -v grubby >/dev/null 2>&1; then sudo grubby --update-kernel=ALL \ --args="rd.driver.blacklist=nouveau modprobe.blacklist=nouveau nvidia-drm.modeset=1" log "Kernel arguments set for every installed kernel" else warn "grubby is not installed; nouveau was not blacklisted" fi # Suspend and resume are where a proprietary driver most visibly fails. # These units save and restore VRAM across it. sudo systemctl enable nvidia-hibernate.service nvidia-suspend.service \ nvidia-resume.service nvidia-powerd.service log "NVIDIA power management services enabled" else warn "The NVIDIA driver did not install; skipping its kernel arguments and services" fi fi fi # ── Secure Boot ────────────────────────────────────────────────────────────── # # akmods signs the modules it builds with a key it generates on installation. # Under Secure Boot that key means nothing until it is enrolled, and enrollment # is deliberately a thing only somebody at the physical machine can complete: # the request is queued here, and the next boot shows a blue screen asking for # the password before it will trust the key. # # The password itself never reaches this stage. The interview hashed it and # recorded the hash, so nothing readable is passed on a command line or left in # this process's environment -- which is the whole reason mokutil has # --generate-hash and --hash-file. mok_hash="${PANAMA_MOK_HASH:-}" if [[ -n "$mok_hash" ]]; then # Overridable so the contract can exercise this against a certificate it is # allowed to create. Nothing else sets it. cert="${PANAMA_MOK_CERT:-/etc/pki/akmods/certs/public_key.der}" if [[ ! -r "$cert" ]]; then warn "No akmods certificate at $cert, so there is no key to enroll" elif mokutil --test-key "$cert" 2>/dev/null | grep -q 'already enrolled'; then log "The akmods key is already enrolled" else hash_file="$(mktemp -t panama-mok.XXXXXX)" chmod 600 "$hash_file" printf '%s\n' "$mok_hash" >"$hash_file" if sudo mokutil --import "$cert" --hash-file "$hash_file"; then log "Key enrollment requested" log "At the next boot, choose 'Enroll MOK' and enter the password you gave the installer" else warn "Key enrollment failed; the NVIDIA module will not load until it is enrolled" fi rm -f "$hash_file" fi fi # ── Fedora's preinstalled extras ───────────────────────────────────────────── if [[ "${PANAMA_DEBLOAT:-no}" == yes ]]; then present=() for package in "${DEBLOAT[@]}"; do rpm -q "$package" >/dev/null 2>&1 && present+=("$package") done if (( ${#present[@]} > 0 )); then log "Removing ${present[*]}" sudo dnf remove -y "${present[@]}" >/dev/null \ || warn "Some packages could not be removed" else log "None of Fedora's extras are installed" fi fi # ── Firmware ───────────────────────────────────────────────────────────────── # # Panama's Updates page covers this from then on; the installer covers the # first run. --no-reboot-check because deciding to reboot is not this stage's # call to make in the middle of an unattended install. if [[ "${PANAMA_FIRMWARE:-no}" == yes ]]; then if command -v fwupdmgr >/dev/null 2>&1; then log "Refreshing firmware metadata" sudo fwupdmgr refresh --force >/dev/null 2>&1 log "Applying firmware updates" sudo fwupdmgr update -y --no-reboot-check \ || log "No firmware updates were applied" else warn "fwupdmgr is not installed; skipping firmware" fi fi