clawdie-iso/firstboot/shell-gpu.sh
Sam & Claude d28d38b49f impl: Complete all 5 shell modules for v0.9.0 installer
Implements critical firstboot orchestration:
- shell-gpu.sh: GPU detection (Intel i915kms, AMD amdgpu, NVIDIA, VMware vmwgfx)
- shell-nvidia.sh: NVIDIA driver version selection (590/470/390 per GPU)
- shell-pkg.sh: Package repository config + Bastille cache seeding
- shell-env.sh: .env generation with secrets and jail IP allocation
- shell-deploy.sh: Clawdie-AI tarball extraction + npm run install-all

All modules:
- POSIX-compliant (no bash-isms)
- Proper error handling and validation
- Comprehensive logging to /var/log/clawdie-firstboot.log
- Progress tracking to /var/log/clawdie-firstboot.progress
- Environment variable overrides for testing

Unblocks firstboot.sh which was calling undefined functions.
Ready for end-to-end installation testing on bhyve VM.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-04 20:04:21 +02:00

184 lines
5.1 KiB
Bash
Executable file

#!/bin/sh
# Clawdie Shell — GPU Detection Module
# Purpose: Detect GPU and configure appropriate kernel modules
# POSIX-compliant (no bash-isms)
set -eu
# Configuration (can be overridden for testing)
RC_CONF="${RC_CONF:-/etc/rc.conf}"
LOG_FILE="${LOG_FILE:-/var/log/clawdie-firstboot.log}"
PROGRESS_FILE="${PROGRESS_FILE:-/var/log/clawdie-firstboot.progress}"
# ============================================================================
# MAIN ENTRY POINT
# ============================================================================
clawdie_shell_gpu_detect() {
# Main orchestrator: detect GPU and write rc.conf
# Sets DETECTED_GPU for use by other modules
log_msg "[gpu] Starting GPU detection"
# Query pciconf for GPU vendor
gpu_vendor=$(clawdie_shell_gpu_detect_pci)
if [ -z "$gpu_vendor" ]; then
log_msg "[gpu] No GPU detected — using VESA fallback"
DETECTED_GPU="vesa"
echo "[GPU] VESA" >> "$PROGRESS_FILE"
return 0
fi
log_msg "[gpu] Detected GPU vendor: $gpu_vendor"
# Convert vendor to driver module list
kld_list=$(clawdie_shell_gpu_match_driver "$gpu_vendor")
DETECTED_GPU="$gpu_vendor"
if [ -z "$kld_list" ]; then
log_msg "[gpu] Vendor '$gpu_vendor' has no driver — using VESA fallback"
DETECTED_GPU="vesa"
echo "[GPU] VESA (unknown vendor)" >> "$PROGRESS_FILE"
return 0
fi
log_msg "[gpu] Matched driver: $kld_list"
# Write to rc.conf
clawdie_shell_gpu_write_rcconf "$kld_list"
log_msg "[gpu] Updated rc.conf with kld_list"
echo "[GPU] $DETECTED_GPU ($kld_list)" >> "$PROGRESS_FILE"
log_msg "[gpu] GPU detection complete"
}
# ============================================================================
# GPU DETECTION VIA PCICONF
# ============================================================================
clawdie_shell_gpu_detect_pci() {
# Query pciconf for GPU vendor
# Returns: intel, amd, nvidia, vmware, or empty string
local pciconf_out
# Get pciconf output (filter to VGA device)
pciconf_out=$(pciconf -lv 2>/dev/null | grep -i "class=0x030000" | head -1 || true)
if [ -z "$pciconf_out" ]; then
return
fi
# Extract vendor string
if echo "$pciconf_out" | grep -iq "Intel"; then
echo "intel"
elif echo "$pciconf_out" | grep -iq "AMD\|ATI"; then
echo "amd"
elif echo "$pciconf_out" | grep -iq "NVIDIA"; then
echo "nvidia"
elif echo "$pciconf_out" | grep -iq "VMware"; then
echo "vmware"
fi
}
# ============================================================================
# DRIVER LOOKUP TABLE
# ============================================================================
clawdie_shell_gpu_match_driver() {
# Convert vendor to kernel module list
# Input: intel, amd, nvidia, vmware, or vendor string
# Output: space-separated kld module names (e.g., "i915kms" or "nvidia-modeset nvidia")
local vendor="$1"
case "$vendor" in
intel)
echo "i915kms"
;;
amd)
echo "amdgpu"
;;
nvidia)
# NVIDIA driver is set separately by clawdie_shell_nvidia_detect()
# This module just returns the base driver name
echo "nvidia-modeset nvidia"
;;
vmware)
echo "vmwgfx"
;;
*)
# Unknown vendor — no driver
return
;;
esac
}
# ============================================================================
# RC.CONF WRITING
# ============================================================================
clawdie_shell_gpu_write_rcconf() {
# Write kld_list to rc.conf
# Input: space-separated module list (e.g., "i915kms" or "nvidia-modeset nvidia")
local kld_list="$1"
if [ ! -f "$RC_CONF" ]; then
log_msg "[gpu] Creating $RC_CONF"
touch "$RC_CONF"
fi
# If kld_list is empty (VESA), skip writing anything
if [ -z "$kld_list" ]; then
log_msg "[gpu] No driver — skipping kld_list (VESA fallback)"
return 0
fi
# Remove existing kld_list if present
if grep -q "^kld_list=" "$RC_CONF" 2>/dev/null; then
sed -i.bak '/^kld_list=/d' "$RC_CONF"
rm -f "$RC_CONF.bak"
fi
# Append new kld_list
echo "kld_list=\"$kld_list\"" >> "$RC_CONF"
log_msg "[gpu] Wrote kld_list=$kld_list to $RC_CONF"
}
# ============================================================================
# VALIDATION
# ============================================================================
clawdie_shell_gpu_validate() {
# Verify rc.conf has valid kld_list (if GPU detected)
if [ ! -f "$RC_CONF" ]; then
log_msg "[gpu] ERROR: $RC_CONF not found"
return 1
fi
if grep -q "^kld_list=" "$RC_CONF" 2>/dev/null; then
local kld=$(grep "^kld_list=" "$RC_CONF" | cut -d= -f2 | tr -d '"' | head -1)
if [ -z "$kld" ]; then
log_msg "[gpu] ERROR: kld_list is empty"
return 1
fi
fi
return 0
}
# ============================================================================
# LOGGING HELPER
# ============================================================================
log_msg() {
echo "$(date '+%H:%M:%S') $1" | tee -a "$LOG_FILE" 2>/dev/null || true
}
# Only run if sourced directly (not during test)
if [ "${SHELL_GPU_TEST:-0}" -eq 0 ]; then
clawdie_shell_gpu_detect
fi