makepad/tools/arch_usb/provision.sh

200 lines
8.9 KiB
Bash

#!/usr/bin/env bash
set -Eeuo pipefail
state=/var/lib/makepad-provision
seed=/run/makepad-seed
mkdir -p "$state" "$seed"
exec > >(tee -a /var/log/makepad-provision.log) 2>&1
trap 'rc=$?; printf "FAILED at line %s (exit %s); see /var/log/makepad-provision.log\n" "$LINENO" "$rc" > "$state/status"; exit "$rc"' ERR
test ! -f "$state/complete" || exit 0
stage() { printf '%s\n' "$*" | tee "$state/status"; }
stage 'Preparing persistent root filesystem'
if ! mountpoint -q "$seed"; then
device=/dev/disk/by-label/CIDATA
test -e "$device" || device=/dev/disk/by-label/cidata
mount -o ro "$device" "$seed"
fi
btrfs filesystem resize max /
test "$(df --output=avail -B1 / | tail -1)" -gt 25000000000
stage 'Verifying USB payload checksums'
(cd "$seed" && sha256sum --quiet -c sha256sums)
if test ! -f "$state/mirror-extracted"; then
stage 'Unpacking the offline Arch package mirror'
mkdir -p /var/cache/makepad-mirror
cat "$seed"/mirror-*.tar | tar --no-same-owner -xf - -C /var/cache/makepad-mirror
touch "$state/mirror-extracted"
fi
stage 'Initializing package signing keys'
pacman-key --init
pacman-key --populate archlinux
stage 'Installing signed Arch packages from the USB cache'
# A temporary config leaves the normal pacman mirror configuration intact.
cat > /run/makepad-pacman.conf <<'EOF'
[options]
Architecture = x86_64
SigLevel = Required DatabaseOptional
LocalFileSigLevel = Required
ParallelDownloads = 8
CacheDir = /var/cache/pacman/pkg
CacheDir = /var/cache/makepad-mirror/core/os/x86_64
CacheDir = /var/cache/makepad-mirror/extra/os/x86_64
[core]
Server = file:///var/cache/makepad-mirror/core/os/x86_64
[extra]
Server = file:///var/cache/makepad-mirror/extra/os/x86_64
EOF
mapfile -t packages < "$seed/requested-packages.txt"
# Match the JACK provider used when resolving the offline package cache.
# Also handles seeds assembled before this provider was an explicit target.
if [[ " ${packages[*]} " != *" pipewire-jack "* ]]; then
packages+=(pipewire-jack)
fi
pacman --config /run/makepad-pacman.conf -U --needed --noconfirm /var/cache/makepad-mirror/core/os/x86_64/archlinux-keyring-*.pkg.tar.zst
# Full upgrade against one consistent repository snapshot; never a partial -Sy.
# Adopt only the Ethernet firmware copied by firstboot before pacman was ready.
pacman --config /run/makepad-pacman.conf -Syu --needed --noconfirm --overwrite 'usr/lib/firmware/rtl_nic/*' "${packages[@]}"
stage 'Configuring graphics, CUDA, sound, and boot'
usermod -aG wheel,audio,video,input,render,storage,uucp,games arch
visudo -cf /etc/sudoers.d/10-arch
cat > /etc/modprobe.d/makepad-nvidia.conf <<'EOF'
options nvidia_drm modeset=1 fbdev=1
EOF
cat > /etc/modprobe.d/makepad-no-nouveau.conf <<'EOF'
blacklist nouveau
options nouveau modeset=0
EOF
mkdir -p /etc/mkinitcpio.conf.d
cat > /etc/mkinitcpio.conf.d/makepad.conf <<'EOF'
MODULES+=(nvidia nvidia_modeset nvidia_uvm nvidia_drm r8169 xhci_pci usbhid)
HOOKS=(base systemd microcode modconf kms keyboard sd-vconsole block filesystems fsck)
EOF
cat > /etc/profile.d/makepad-cuda.sh <<'EOF'
export CUDA_HOME=/opt/cuda
export CUDA_PATH=/opt/cuda
# Builds link CUDA only from a root named here (never a scanned system install).
export MAKEPAD_CUDA_ROOT=/opt/cuda
export NVCC_CCBIN=/usr/bin/g++-15
export CUDAHOSTCXX=/usr/bin/g++-15
case :$PATH: in *:/opt/cuda/bin:*) ;; *) export PATH=/opt/cuda/bin:$PATH ;; esac
EOF
# PAM also supplies these to non-login SSH commands used by build automation.
cat >> /etc/environment <<'EOF'
CUDA_HOME=/opt/cuda
CUDA_PATH=/opt/cuda
MAKEPAD_CUDA_ROOT=/opt/cuda
NVCC_CCBIN=/usr/bin/g++-15
CUDAHOSTCXX=/usr/bin/g++-15
EOF
printf '/opt/cuda/lib64\n/opt/cuda/targets/x86_64-linux/lib\n' > /etc/ld.so.conf.d/makepad-cuda.conf
ldconfig
sed -i '/^GRUB_CMDLINE_LINUX_DEFAULT=/c\GRUB_CMDLINE_LINUX_DEFAULT="rootflags=compress=zstd:1 nvidia_drm.modeset=1 nvidia_drm.fbdev=1 console=tty1 loglevel=3 module_blacklist=bluetooth,btusb"' /etc/default/grub
sed -i '/^GRUB_TERMINAL=/c\GRUB_TERMINAL="console"' /etc/default/grub
sed -i '/^GRUB_TIMEOUT=/c\GRUB_TIMEOUT=0' /etc/default/grub
if grep -q '^GRUB_TIMEOUT_STYLE=' /etc/default/grub; then
sed -i '/^GRUB_TIMEOUT_STYLE=/c\GRUB_TIMEOUT_STYLE=hidden' /etc/default/grub
else
printf 'GRUB_TIMEOUT_STYLE=hidden\n' >> /etc/default/grub
fi
mkinitcpio -P
grub-mkconfig -o /boot/grub/grub.cfg
systemctl set-default multi-user.target
systemctl enable sshd systemd-resolved systemd-timesyncd
systemctl mask systemd-networkd-wait-online.service systemd-time-wait-sync.service pacman-init.service bluetooth.service wpa_supplicant.service
systemctl --global enable pipewire.socket pipewire-pulse.socket wireplumber.service
loginctl enable-linger arch
systemctl enable --now makepad-mount-win.service
systemctl unmask iwd.service
systemctl enable --now iwd.service
networkctl reload
stage 'Installing pinned Fanatec driver source and DKMS module'
fanatec_version=0.0.dd78ef477c0d
fanatec_source=/usr/src/hid-fanatec-$fanatec_version
mkdir -p "$fanatec_source"
tar -xzf "$seed/fanatec.tgz" --strip-components=1 -C "$fanatec_source"
find "$fanatec_source" -type f \( -name dkms.conf -o -name '*.c' \) -exec sed -i "s/#VERSION#/$fanatec_version/g" {} +
install -m 0644 "$fanatec_source/fanatec.rules" /etc/udev/rules.d/99-fanatec.rules
if ! dkms status -m hid-fanatec -v "$fanatec_version" | grep -q .; then
dkms add -m hid-fanatec -v "$fanatec_version"
fi
fanatec_ok=yes
for directory in /usr/lib/modules/*; do
test -d "$directory/build" || continue
kernel=${directory##*/}
if ! dkms install -m hid-fanatec -v "$fanatec_version" -k "$kernel"; then
fanatec_ok=no
fi
done
printf '%s\n' "$fanatec_ok" > "$state/fanatec-built"
install -o root -g root -m 0755 "$seed/gbelt-bind.sh" /usr/local/sbin/makepad-gbelt-bind
install -o root -g root -m 0644 "$seed/70-makepad-game-hardware.rules" /etc/udev/rules.d/70-makepad-game-hardware.rules
udevadm control --reload-rules
stage 'Unpacking the Makepad source snapshot and Cargo cache'
mkdir -p /home/arch/makepad /home/arch/.cargo
if test ! -f "$state/source-installed"; then
tar -xzf "$seed/makepad-source.tgz" -C /home/arch/makepad
tar -xf "$seed/cargo-cache.tar" -C /home/arch/.cargo
touch "$state/source-installed"
fi
stage 'Installing the offline Linux CEF distribution'
cef_root=/home/arch/makepad/local/cef-prebuilt
cef_directory=$(cat "$seed/cef-directory.txt")
[[ "$cef_directory" = cef_binary_*_linux64 && "$cef_directory" != */* ]]
mkdir -p "$cef_root"
if test ! -f "$state/cef-installed"; then
tar --no-same-owner -xjf "$seed/cef-linux.bz2" -C "$cef_root"
test -f "$cef_root/$cef_directory/Release/libcef.so"
ln -sfn "$cef_directory" "$cef_root/current-linux64"
touch "$state/cef-installed"
fi
chown -R arch:arch /home/arch/makepad /home/arch/.cargo
install -o arch -g arch -m 0644 "$seed/source-revision.txt" /home/arch/makepad/SOURCE-REVISION.txt
runuser -u arch -- git -C /home/arch/makepad init
runuser -u arch -- git -C /home/arch/makepad lfs install --local
stage 'Installing the direct Vulkan WM launcher'
install -d /etc/makepad
install -m 0755 "$seed/wm-session.sh" /usr/local/bin/makepad-wm-session
install -m 0644 "$seed/wm.env" /etc/makepad/wm.env
install -m 0644 "$seed/makepad-wm.service" /etc/systemd/system/makepad-wm.service
install -m 0755 "$seed/aihub-session.sh" /usr/local/bin/makepad-aihub-session
install -m 0644 "$seed/aihub.env" /etc/makepad/aihub.env
install -m 0644 "$seed/makepad-aihub.service" /etc/systemd/system/makepad-aihub.service
systemctl daemon-reload
systemctl enable makepad-wm.service makepad-aihub.service
stage 'Recording installed tool versions'
source /etc/profile.d/makepad-cuda.sh
{
rustc --version
cargo --version
nvcc --version
pacman -Q linux nvidia-open nvidia-utils cuda cudnn
lspci -nnk
lsusb
dkms status
} > "$state/installed.txt" 2>&1
if test -f "$seed/clone.json"; then
stage 'Installing the verified release WM and AI Hub from the working clone'
install -d -o arch -g arch /home/arch/makepad/target/release
install -o arch -g arch -m 0755 "$seed/wm" /home/arch/makepad/target/release/wm
install -o arch -g arch -m 0755 "$seed/makepad-ai-hub" /home/arch/makepad/target/release/makepad-ai-hub
install -o arch -g arch -m 0644 "$seed/clone.json" /home/arch/makepad/CLONE-REVISION.json
else
stage 'Building release WM and CUDA AI Hub offline'
runuser -u arch -- env HOME=/home/arch MAKEPAD=linux_direct+vulkan CARGO_NET_OFFLINE=true MAKEPAD_CEF_OFFLINE=1 MAKEPAD_CUDA_ROOT=/opt/cuda NVCC_CCBIN=/usr/bin/g++-15 CUDAHOSTCXX=/usr/bin/g++-15 PATH="$PATH" bash -c 'cd /home/arch/makepad && cargo build --offline --release -p makepad-wm -p makepad-app-ai-hub'
fi
sshd -t
systemctl reload sshd
touch "$state/complete"
touch /etc/cloud/cloud-init.disabled
if test "$fanatec_ok" = yes; then
stage 'Package setup complete. Reboot required for the installed kernel and NVIDIA driver.'
else
stage 'Package setup complete; Fanatec DKMS needs inspection. Reboot required for the installed kernel/NVIDIA driver.'
fi
# Keep SSH available for inspection. The operator can reboot when ready.