Enhance first-boot script and documentation with config file support

Introduce a configuration file (`first-boot.conf`) to allow users to override default script variables without modifying the script directly. Update the first-boot script to load this config file from multiple locations, enhancing flexibility in customization. Revise documentation to guide users on how to utilize the config file for setting variables like FILE_SERVER, HOSTNAME, and PACKAGES, improving the overall user experience during first boot operations.
This commit is contained in:
nearxos
2026-02-21 22:22:40 +02:00
parent 3909fd7cf1
commit 79a7f76a12
4 changed files with 157 additions and 43 deletions

View File

@@ -1,26 +1,51 @@
#!/bin/bash
# First-boot: packages, Chromium kiosk, rpd-labwc + touch, reTerminal DM drivers.
# Run by cloud-init (user-data-remote-gnss.example). Run as root.
# Optional: copy first-boot.conf.example to first-boot.conf and edit; it is loaded
# from the script dir, /tmp/first-boot.conf, or /etc/cm4-provisioning/first-boot.conf.
set -e
export DEBIAN_FRONTEND=noninteractive
# --- Constants ---
# All first-boot assets live in portal-files/first-boot/ on the file server.
FILE_SERVER="http://10.20.50.1:5000/files/first-boot"
HOSTNAME="guard"
PI_USER="pi"
# --- Defaults (overridden by first-boot.conf if present) ---
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-.}")" 2>/dev/null && pwd)"
FILE_SERVER="${FILE_SERVER:-http://10.20.50.1:5000/files/first-boot}"
HOSTNAME="${HOSTNAME:-guard}"
PI_USER="${PI_USER:-pi}"
LOGFILE="${LOGFILE:-/var/log/first-boot.log}"
PLYMOUTH_DIR="${PLYMOUTH_DIR:-/usr/share/plymouth/themes/custom}"
WALLPAPER_PATH="${WALLPAPER_PATH:-/usr/share/rpd-wallpaper/splash.png}"
PACKAGES="${PACKAGES:-git chromium wmctrl openssh-server swaybg wlr-randr maliit-keyboard xinput-calibrator}"
LIGHTDM_SESSION="${LIGHTDM_SESSION:-rpd-labwc}"
GTK_THEME_NAME="${GTK_THEME_NAME:-PiXnoir}"
WALLPAPER_MODE="${WALLPAPER_MODE:-crop}"
DSI_ROTATE="${DSI_ROTATE:-90}"
SWIOTLB_SIZE="${SWIOTLB_SIZE:-65536}"
RETERMINAL_DEVICE="${RETERMINAL_DEVICE:-reTerminal-DM}"
RETERMINAL_REPO_URL="${RETERMINAL_REPO_URL:-https://github.com/Seeed-Studio/seeed-linux-dtoverlays}"
ONESHOT_SCRIPTS="${ONESHOT_SCRIPTS:-}"
# --- Load config file (first found) ---
FIRST_BOOT_CONF=""
for _f in "$SCRIPT_DIR/first-boot.conf" /tmp/first-boot.conf /etc/cm4-provisioning/first-boot.conf; do
if [[ -f "$_f" ]]; then
# shellcheck source=first-boot.conf.example
set -a && source "$_f" && set +a
FIRST_BOOT_CONF="$_f"
break
fi
done
# --- Derived paths ---
PI_HOME="/home/$PI_USER"
AUTOSTART="$PI_HOME/.config/autostart"
LOGFILE="/var/log/first-boot.log"
PLYMOUTH_DIR="/usr/share/plymouth/themes/custom"
WALLPAPER_PATH="/usr/share/rpd-wallpaper/splash.png"
# --- Logging ---
log() { echo "[$(date -Iseconds)] $*"; }
exec > >(tee -a "$LOGFILE") 2>&1
log "=== first-boot.sh started ==="
log "FILE_SERVER=$FILE_SERVER PI_USER=$PI_USER LOGFILE=$LOGFILE"
[[ -n "$FIRST_BOOT_CONF" ]] && log "Config loaded from $FIRST_BOOT_CONF" || log "Using built-in defaults (no config file found)"
log "FILE_SERVER=$FILE_SERVER PI_USER=$PI_USER HOSTNAME=$HOSTNAME LOGFILE=$LOGFILE"
# --- 0. Hostname and /etc/hosts (avoids "unable to resolve host" with sudo) ---
log "--- Hostname: $HOSTNAME ---"
@@ -57,9 +82,8 @@ install_oneshot() {
log "--- Installing packages ---"
log "Running apt-get update ..."
apt-get update -qq
log "Installing: git chromium wmctrl openssh-server swaybg wlr-randr maliit-keyboard xinput-calibrator"
apt-get install -y -qq git chromium wmctrl openssh-server \
swaybg wlr-randr maliit-keyboard xinput-calibrator
log "Installing: $PACKAGES"
apt-get install -y -qq $PACKAGES
log "Packages installed successfully"
# --- 2. Dirs and kiosk files from file server ---
@@ -99,10 +123,10 @@ if curl -fsSL "${FILE_SERVER}/splash.png" -o "$PLYMOUTH_DIR/splash.png"; then
PCMANFM_DESKTOP="$PI_HOME/.config/pcmanfm/$PROFILE/desktop-items-0.conf"
mkdir -p "$(dirname "$PCMANFM_DESKTOP")"
if [[ ! -f "$PCMANFM_DESKTOP" ]]; then
printf '%s\n' '[*]' "wallpaper=$WALLPAPER_PATH" 'wallpaper_mode=crop' 'wallpaper_common=1' > "$PCMANFM_DESKTOP"
printf '%s\n' '[*]' "wallpaper=$WALLPAPER_PATH" "wallpaper_mode=$WALLPAPER_MODE" 'wallpaper_common=1' > "$PCMANFM_DESKTOP"
else
grep -q '^wallpaper=' "$PCMANFM_DESKTOP" && sed -i "s|^wallpaper=.*|wallpaper=$WALLPAPER_PATH|" "$PCMANFM_DESKTOP" || echo "wallpaper=$WALLPAPER_PATH" >> "$PCMANFM_DESKTOP"
grep -q '^wallpaper_mode=' "$PCMANFM_DESKTOP" && sed -i 's/^wallpaper_mode=.*/wallpaper_mode=crop/' "$PCMANFM_DESKTOP" || echo 'wallpaper_mode=crop' >> "$PCMANFM_DESKTOP"
grep -q '^wallpaper_mode=' "$PCMANFM_DESKTOP" && sed -i "s/^wallpaper_mode=.*/wallpaper_mode=$WALLPAPER_MODE/" "$PCMANFM_DESKTOP" || echo "wallpaper_mode=$WALLPAPER_MODE" >> "$PCMANFM_DESKTOP"
fi
chown -R "$PI_USER:$PI_USER" "$(dirname "$PCMANFM_DESKTOP")"
done
@@ -122,9 +146,9 @@ else
fi
# Raspberry Pi OS may apply main lightdm.conf after .conf.d; force session in main config too
if [[ -f /etc/lightdm/lightdm.conf ]]; then
sed -i 's/^user-session=.*/user-session=rpd-labwc/' /etc/lightdm/lightdm.conf
sed -i 's/^autologin-session=.*/autologin-session=rpd-labwc/' /etc/lightdm/lightdm.conf
log "Patched /etc/lightdm/lightdm.conf to use rpd-labwc"
sed -i "s/^user-session=.*/user-session=$LIGHTDM_SESSION/" /etc/lightdm/lightdm.conf
sed -i "s/^autologin-session=.*/autologin-session=$LIGHTDM_SESSION/" /etc/lightdm/lightdm.conf
log "Patched /etc/lightdm/lightdm.conf to use $LIGHTDM_SESSION"
fi
# --- 5. Maliit on-screen keyboard (from file server) ---
@@ -137,29 +161,33 @@ log "--- Dark theme ---"
GTK_SETTINGS="$PI_HOME/.config/gtk-3.0/settings.ini"
mkdir -p "$(dirname "$GTK_SETTINGS")"
if [[ ! -f "$GTK_SETTINGS" ]]; then
printf '%s\n' '[Settings]' 'gtk-application-prefer-dark-theme=1' 'gtk-theme-name=PiXnoir' > "$GTK_SETTINGS"
printf '%s\n' '[Settings]' 'gtk-application-prefer-dark-theme=1' "gtk-theme-name=$GTK_THEME_NAME" > "$GTK_SETTINGS"
else
grep -q '^gtk-application-prefer-dark-theme=' "$GTK_SETTINGS" && sed -i 's/^gtk-application-prefer-dark-theme=.*/gtk-application-prefer-dark-theme=1/' "$GTK_SETTINGS" || echo 'gtk-application-prefer-dark-theme=1' >> "$GTK_SETTINGS"
grep -q '^gtk-theme-name=' "$GTK_SETTINGS" && sed -i 's/^gtk-theme-name=.*/gtk-theme-name=PiXnoir/' "$GTK_SETTINGS" || echo 'gtk-theme-name=PiXnoir' >> "$GTK_SETTINGS"
grep -q '^gtk-theme-name=' "$GTK_SETTINGS" && sed -i "s/^gtk-theme-name=.*/gtk-theme-name=$GTK_THEME_NAME/" "$GTK_SETTINGS" || echo "gtk-theme-name=$GTK_THEME_NAME" >> "$GTK_SETTINGS"
fi
# Fallback if PiXnoir not installed (e.g. older image): Adwaita-dark
log "Set dark theme (PiXnoir) in gtk-3.0/settings.ini"
# Fallback if theme not installed (e.g. older image): Adwaita-dark
log "Set dark theme ($GTK_THEME_NAME) in gtk-3.0/settings.ini"
chown -R "$PI_USER:$PI_USER" "$PI_HOME/.config"
# --- 6. reTerminal DM drivers (Seeed) ---
log "--- reTerminal DM drivers ---"
REPO_DIR="/tmp/seeed-linux-dtoverlays"
log "Cloning seeed-linux-dtoverlays to $REPO_DIR ..."
git clone --depth 1 https://github.com/Seeed-Studio/seeed-linux-dtoverlays "$REPO_DIR"
# Script must run from repo root (it uses pwd for MOD_PATH). On bookworm+ --compat-kernel is not supported.
log "Running reTerminal.sh --device reTerminal-DM from $REPO_DIR ..."
if ( cd "$REPO_DIR" && "$REPO_DIR/scripts/reTerminal.sh" --device reTerminal-DM ); then
log "reTerminal DM drivers installed (reboot will apply)"
if [[ -n "$RETERMINAL_REPO_URL" ]]; then
log "--- reTerminal DM drivers ---"
REPO_DIR="/tmp/seeed-linux-dtoverlays"
log "Cloning seeed-linux-dtoverlays to $REPO_DIR ..."
git clone --depth 1 "$RETERMINAL_REPO_URL" "$REPO_DIR"
# Script must run from repo root (it uses pwd for MOD_PATH). On bookworm+ --compat-kernel is not supported.
log "Running reTerminal.sh --device $RETERMINAL_DEVICE from $REPO_DIR ..."
if ( cd "$REPO_DIR" && "$REPO_DIR/scripts/reTerminal.sh" --device "$RETERMINAL_DEVICE" ); then
log "reTerminal DM drivers installed (reboot will apply)"
else
log "WARNING: reTerminal.sh failed (see log above). Display/touch may still work; you can retry later with: cd $REPO_DIR && sudo ./scripts/reTerminal.sh --device $RETERMINAL_DEVICE"
fi
log "Removing $REPO_DIR"
rm -rf "$REPO_DIR"
else
log "WARNING: reTerminal.sh failed (see log above). Display/touch may still work; you can retry later with: cd $REPO_DIR && sudo ./scripts/reTerminal.sh --device reTerminal-DM"
log "--- Skipping reTerminal drivers (RETERMINAL_REPO_URL not set) ---"
fi
log "Removing $REPO_DIR"
rm -rf "$REPO_DIR"
# --- 6b. Re-apply splash and display (Seeed script sets disable_splash=1 and can duplicate Plymouth theme) ---
log "--- Re-applying boot splash and Plymouth theme ---"
@@ -186,21 +214,29 @@ update-initramfs -u -k all 2>/dev/null || true
CMDLINE_PATH="/boot/firmware/cmdline.txt"
[[ -f "$CMDLINE_PATH" ]] || CMDLINE_PATH="/boot/cmdline.txt"
if [[ -f "$CMDLINE_PATH" ]]; then
if ! grep -q 'swiotlb=' "$CMDLINE_PATH"; then
sed -i 's/rootwait/rootwait swiotlb=65536/' "$CMDLINE_PATH"
log "Added swiotlb=65536 to kernel cmdline (vc4-drm / DSI)"
if [[ -n "$SWIOTLB_SIZE" ]] && ! grep -q 'swiotlb=' "$CMDLINE_PATH"; then
sed -i "s/rootwait/rootwait swiotlb=$SWIOTLB_SIZE/" "$CMDLINE_PATH"
log "Added swiotlb=$SWIOTLB_SIZE to kernel cmdline (vc4-drm / DSI)"
fi
# Persistent rotation for DSI-1 (KMS): append at end of single line. 90 = 90° clockwise.
if ! grep -q 'video=DSI-1:rotate=' "$CMDLINE_PATH"; then
sed -i 's/$/ video=DSI-1:rotate=90/' "$CMDLINE_PATH"
log "Added video=DSI-1:rotate=90 to kernel cmdline (DSI rotation)"
if [[ -n "$DSI_ROTATE" ]] && ! grep -q 'video=DSI-1:rotate=' "$CMDLINE_PATH"; then
sed -i "s/\$/ video=DSI-1:rotate=$DSI_ROTATE/" "$CMDLINE_PATH"
log "Added video=DSI-1:rotate=$DSI_ROTATE to kernel cmdline (DSI rotation)"
fi
fi
# --- 7. One-shots (wallpaper already set in pcmanfm config above; rotation is via cmdline.txt) ---
log "--- One-shot scripts (if any) ---"
# Rotation is set persistently in cmdline.txt (video=DSI-1:rotate=90), not via one-shot script.
log "Rotation is set via kernel cmdline (video=DSI-1:rotate=90)"
if [[ -n "$DSI_ROTATE" ]]; then
log "Rotation is set via kernel cmdline (video=DSI-1:rotate=$DSI_ROTATE)"
fi
if [[ -n "$ONESHOT_SCRIPTS" ]]; then
for _name in $ONESHOT_SCRIPTS; do
install_oneshot "$_name" || true
done
else
log "No one-shot scripts configured (ONESHOT_SCRIPTS empty)"
fi
# --- 8. Allow pi to append to first-boot.log (for one-shot scripts) ---
chmod 666 "$LOGFILE"