🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
658 lines
25 KiB
Bash
Executable File
658 lines
25 KiB
Bash
Executable File
#!/bin/bash
|
||
# Comprehensive Pre-Flight Validation for Dangerous Pi Builds
|
||
# Catches errors BEFORE wasting hours on failed builds
|
||
# Usage: ./scripts/preflight-check.sh
|
||
|
||
# Don't use set -e - we want to collect ALL errors, not stop on first one
|
||
set +e
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||
PI_GEN_DIR="/home/work/pi-gen-builder"
|
||
|
||
# Colors
|
||
RED='\033[0;31m'
|
||
YELLOW='\033[1;33m'
|
||
GREEN='\033[0;32m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
ERRORS=0
|
||
WARNINGS=0
|
||
CHECKS_PASSED=0
|
||
|
||
error() {
|
||
echo -e "${RED}✗ ERROR:${NC} $1"
|
||
((ERRORS++))
|
||
}
|
||
|
||
warn() {
|
||
echo -e "${YELLOW}⚠ WARNING:${NC} $1"
|
||
((WARNINGS++))
|
||
}
|
||
|
||
pass() {
|
||
echo -e "${GREEN}✓${NC} $1"
|
||
((CHECKS_PASSED++))
|
||
}
|
||
|
||
info() {
|
||
echo -e "${BLUE}ℹ${NC} $1"
|
||
}
|
||
|
||
section() {
|
||
echo ""
|
||
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
|
||
echo -e "${BLUE}$1${NC}"
|
||
echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
|
||
}
|
||
|
||
echo ""
|
||
echo "╔════════════════════════════════════════════════════════════╗"
|
||
echo "║ DANGEROUS PI BUILD PRE-FLIGHT VALIDATION ║"
|
||
echo "╚════════════════════════════════════════════════════════════╝"
|
||
echo ""
|
||
|
||
# ============================================================================
|
||
section "1. PI-GEN ENVIRONMENT CHECKS"
|
||
# ============================================================================
|
||
|
||
# Check if pi-gen directory exists
|
||
if [ -d "$PI_GEN_DIR" ]; then
|
||
pass "Pi-gen directory exists: $PI_GEN_DIR"
|
||
else
|
||
error "Pi-gen directory not found: $PI_GEN_DIR"
|
||
fi
|
||
|
||
# Check Docker availability
|
||
if command -v docker &> /dev/null; then
|
||
if docker ps &> /dev/null; then
|
||
pass "Docker is available and accessible"
|
||
else
|
||
error "Docker command exists but cannot connect (check permissions)"
|
||
fi
|
||
else
|
||
error "Docker is not installed or not in PATH"
|
||
fi
|
||
|
||
# Check qemu registration
|
||
if [ -f "/proc/sys/fs/binfmt_misc/qemu-aarch64" ]; then
|
||
if grep -q "enabled" /proc/sys/fs/binfmt_misc/qemu-aarch64; then
|
||
pass "qemu-aarch64 is registered and enabled"
|
||
else
|
||
warn "qemu-aarch64 exists but may not be enabled"
|
||
fi
|
||
else
|
||
warn "qemu-aarch64 not registered (will be registered during build)"
|
||
fi
|
||
|
||
# ============================================================================
|
||
section "2. CONFIGURATION FILE VALIDATION"
|
||
# ============================================================================
|
||
|
||
CONFIG_FILE="$PROJECT_DIR/pi-gen/config"
|
||
if [ -f "$CONFIG_FILE" ]; then
|
||
pass "Config file exists: $CONFIG_FILE"
|
||
|
||
# Check required variables
|
||
for var in IMG_NAME RELEASE STAGE_LIST FIRST_USER_NAME; do
|
||
if grep -q "^$var=" "$CONFIG_FILE"; then
|
||
value=$(grep "^$var=" "$CONFIG_FILE" | cut -d'=' -f2- | tr -d '"')
|
||
pass "Config has $var=$value"
|
||
else
|
||
error "Config missing required variable: $var"
|
||
fi
|
||
done
|
||
|
||
# Check QCOW2 setting
|
||
if grep -q "USE_QCOW2=1" "$CONFIG_FILE"; then
|
||
pass "QCOW2 caching enabled (fast incremental builds)"
|
||
else
|
||
warn "QCOW2 caching disabled (slow rebuilds)"
|
||
fi
|
||
else
|
||
error "Config file not found: $CONFIG_FILE"
|
||
fi
|
||
|
||
# ============================================================================
|
||
section "3. STAGE STRUCTURE VALIDATION"
|
||
# ============================================================================
|
||
|
||
# Get list of custom stages from config
|
||
CUSTOM_STAGES=$(grep "^STAGE_LIST=" "$CONFIG_FILE" | cut -d'"' -f2 | grep -oE 'stage[A-Za-z0-9_]+' | grep -v '^stage[0-9]$')
|
||
|
||
for stage in $CUSTOM_STAGES; do
|
||
STAGE_DIR="$PROJECT_DIR/pi-gen/$stage"
|
||
|
||
if [ ! -d "$STAGE_DIR" ]; then
|
||
error "Stage directory does not exist: $STAGE_DIR"
|
||
continue
|
||
fi
|
||
|
||
info "Checking stage: $stage"
|
||
|
||
# Check for prerun.sh (CRITICAL - this was the bug!)
|
||
if [ -f "$STAGE_DIR/prerun.sh" ]; then
|
||
pass " Has prerun.sh"
|
||
|
||
# Check if prerun.sh contains copy_previous
|
||
if grep -q "copy_previous" "$STAGE_DIR/prerun.sh"; then
|
||
pass " prerun.sh calls copy_previous"
|
||
else
|
||
error " prerun.sh exists but doesn't call copy_previous"
|
||
info " This will cause: 'Unable to chroot' error"
|
||
fi
|
||
|
||
# Check if executable
|
||
if [ -x "$STAGE_DIR/prerun.sh" ]; then
|
||
pass " prerun.sh is executable"
|
||
else
|
||
warn " prerun.sh is not executable (should be chmod +x)"
|
||
fi
|
||
else
|
||
# Only error if this is not stage0 (stage0 doesn't need prerun.sh)
|
||
if [ "$stage" != "stage0" ]; then
|
||
error " MISSING prerun.sh (CRITICAL)"
|
||
info " This will cause: 'No such file or directory' for rootfs"
|
||
info " Fix: Create prerun.sh with copy_previous function"
|
||
fi
|
||
fi
|
||
|
||
# Check for EXPORT_IMAGE
|
||
if [ -f "$STAGE_DIR/EXPORT_IMAGE" ]; then
|
||
pass " Has EXPORT_IMAGE"
|
||
|
||
# Validate EXPORT_IMAGE syntax
|
||
if grep -q "IMG_SUFFIX" "$STAGE_DIR/EXPORT_IMAGE"; then
|
||
pass " EXPORT_IMAGE has IMG_SUFFIX"
|
||
else
|
||
warn " EXPORT_IMAGE missing IMG_SUFFIX"
|
||
fi
|
||
else
|
||
warn " No EXPORT_IMAGE (stage won't create image)"
|
||
fi
|
||
|
||
# Check for substages
|
||
substage_count=$(find "$STAGE_DIR" -maxdepth 1 -type d -name '[0-9][0-9]*' | wc -l)
|
||
if [ $substage_count -eq 0 ]; then
|
||
warn " No substages found (stage does nothing)"
|
||
else
|
||
pass " Found $substage_count substage(s)"
|
||
fi
|
||
done
|
||
|
||
# ============================================================================
|
||
section "4. BUILD SCRIPT SYNTAX VALIDATION"
|
||
# ============================================================================
|
||
|
||
info "Checking all stage scripts for syntax errors..."
|
||
|
||
for script in "$PROJECT_DIR"/pi-gen/stage*/*/[0-9][0-9]-*.sh; do
|
||
if [ -f "$script" ]; then
|
||
if bash -n "$script" 2>/dev/null; then
|
||
pass " $(basename $(dirname $(dirname "$script")))/$(basename $(dirname "$script"))/$(basename "$script")"
|
||
else
|
||
error " Syntax error in: $script"
|
||
bash -n "$script" 2>&1 | sed 's/^/ /'
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Check prerun.sh files
|
||
for script in "$PROJECT_DIR"/pi-gen/stage*/prerun.sh; do
|
||
if [ -f "$script" ]; then
|
||
if bash -n "$script" 2>/dev/null; then
|
||
pass " $(basename $(dirname "$script"))/prerun.sh"
|
||
else
|
||
error " Syntax error in: $script"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# ============================================================================
|
||
section "5. DEPENDENCY CHECKS IN SCRIPTS"
|
||
# ============================================================================
|
||
|
||
info "Checking if commands are installed before use..."
|
||
|
||
# Check PM3 stage for cmake before use
|
||
PM3_SCRIPT="$PROJECT_DIR/pi-gen/stage*/01-proxmark3/00-run-chroot.sh"
|
||
if ls $PM3_SCRIPT 2>/dev/null | head -1 | xargs -I {} bash -c '
|
||
script="$1"
|
||
if grep -q "cmake" "$script"; then
|
||
if grep -B50 "cmake" "$script" | grep -q "apt-get install.*cmake"; then
|
||
echo "PASS"
|
||
else
|
||
echo "FAIL"
|
||
fi
|
||
else
|
||
echo "SKIP"
|
||
fi
|
||
' _ {} | grep -q "PASS"; then
|
||
pass " PM3: cmake installed before use"
|
||
elif ls $PM3_SCRIPT 2>/dev/null | head -1 | xargs -I {} bash -c '
|
||
script="$1"
|
||
if grep -q "cmake" "$script"; then
|
||
if grep -B50 "cmake" "$script" | grep -q "apt-get install.*cmake"; then
|
||
echo "PASS"
|
||
else
|
||
echo "FAIL"
|
||
fi
|
||
else
|
||
echo "SKIP"
|
||
fi
|
||
' _ {} | grep -q "FAIL"; then
|
||
warn " PM3: cmake may not be installed before use"
|
||
fi
|
||
|
||
# Check dangerous-pi stage for pip3
|
||
DTPI_SCRIPT="$PROJECT_DIR/pi-gen/stage*/*/03-dangerous-pi/00-run-chroot.sh"
|
||
if ls $DTPI_SCRIPT 2>/dev/null | head -1 | xargs -I {} bash -c '
|
||
script="$1"
|
||
if grep -q "pip3 install" "$script"; then
|
||
if grep -B20 "pip3 install" "$script" | grep -qE "apt-get install.*python3-pip|command -v pip3"; then
|
||
echo "PASS"
|
||
else
|
||
echo "FAIL"
|
||
fi
|
||
else
|
||
echo "SKIP"
|
||
fi
|
||
' _ {} | grep -q "PASS"; then
|
||
pass " Dangerous-Pi: pip3 check before use"
|
||
elif ls $DTPI_SCRIPT 2>/dev/null | head -1 | xargs -I {} bash -c '
|
||
script="$1"
|
||
if grep -q "pip3 install" "$script"; then
|
||
if grep -B20 "pip3 install" "$script" | grep -qE "apt-get install.*python3-pip|command -v pip3"; then
|
||
echo "PASS"
|
||
else
|
||
echo "FAIL"
|
||
fi
|
||
else
|
||
echo "SKIP"
|
||
fi
|
||
' _ {} | grep -q "FAIL"; then
|
||
error " Dangerous-Pi: pip3 used without installation check"
|
||
fi
|
||
|
||
# Check PM3 dependencies by analyzing source
|
||
info "Analyzing PM3 source for required dependencies..."
|
||
PM3_SCRIPT_PATH="$PROJECT_DIR/pi-gen/stagePM3/01-proxmark3/00-run-chroot.sh"
|
||
|
||
if [ -f "$PM3_SCRIPT_PATH" ]; then
|
||
# Clone PM3 temporarily to analyze (lightweight, just for analysis)
|
||
PM3_TEMP="/tmp/pm3-preflight-check"
|
||
if [ ! -d "$PM3_TEMP" ]; then
|
||
info "Cloning Proxmark3 for dependency analysis..."
|
||
git clone --depth 1 --quiet https://github.com/RfidResearchGroup/proxmark3 "$PM3_TEMP" 2>/dev/null
|
||
fi
|
||
|
||
if [ -d "$PM3_TEMP" ]; then
|
||
# Header to package mapping (common Debian packages)
|
||
declare -A HEADER_TO_PKG=(
|
||
["lz4frame.h"]="liblz4-dev"
|
||
["lz4.h"]="liblz4-dev"
|
||
["readline/readline.h"]="libreadline-dev"
|
||
["readline.h"]="libreadline-dev"
|
||
["libusb.h"]="libusb-1.0-0-dev"
|
||
["libusb-1.0/libusb.h"]="libusb-1.0-0-dev"
|
||
["pthread.h"]="libc6-dev"
|
||
["zlib.h"]="zlib1g-dev"
|
||
["bzlib.h"]="libbz2-dev"
|
||
["jansson.h"]="libjansson-dev"
|
||
["bluez/bluetooth.h"]="libbluetooth-dev"
|
||
)
|
||
|
||
# Find all #include statements for system headers
|
||
FOUND_HEADERS=$(grep -rh "^#include <" "$PM3_TEMP/client" 2>/dev/null | \
|
||
grep -oE '<[^>]+>' | tr -d '<>' | sort -u)
|
||
|
||
# Check if required packages are installed
|
||
for header in $FOUND_HEADERS; do
|
||
pkg="${HEADER_TO_PKG[$header]}"
|
||
if [ -n "$pkg" ]; then
|
||
# Check if this package is in our install script
|
||
if grep -q "$pkg" "$PM3_SCRIPT_PATH"; then
|
||
pass " PM3: $pkg (for $header)"
|
||
else
|
||
error " PM3: Missing $pkg (required for #include <$header>)"
|
||
info " Add '$pkg' to apt-get install in stagePM3/01-proxmark3/00-run-chroot.sh"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# Also check for essential build tools
|
||
ESSENTIAL_DEPS=("cmake" "build-essential" "git" "pkg-config")
|
||
for dep in "${ESSENTIAL_DEPS[@]}"; do
|
||
if grep -q "$dep" "$PM3_SCRIPT_PATH"; then
|
||
pass " PM3: $dep (build tool)"
|
||
else
|
||
error " PM3: Missing $dep (essential build tool)"
|
||
info " Add '$dep' to apt-get install in stagePM3/01-proxmark3/00-run-chroot.sh"
|
||
fi
|
||
done
|
||
else
|
||
warn " Could not clone PM3 for analysis - using basic checks only"
|
||
# Fallback to basic check
|
||
for dep in cmake build-essential git; do
|
||
if grep -q "$dep" "$PM3_SCRIPT_PATH"; then
|
||
pass " PM3: $dep"
|
||
else
|
||
error " PM3: Missing $dep"
|
||
fi
|
||
done
|
||
fi
|
||
fi
|
||
|
||
# ============================================================================
|
||
section "6. DIRECTORY CREATION VALIDATION"
|
||
# ============================================================================
|
||
|
||
info "Checking for mkdir -p before file writes to non-standard dirs..."
|
||
|
||
WIFI_SCRIPT="$PROJECT_DIR/pi-gen/stage*/*/01-Wireless-AP/00-run-chroot.sh"
|
||
if [ -f "$(ls $WIFI_SCRIPT 2>/dev/null | head -1)" ]; then
|
||
# Check /etc/network/interfaces.d
|
||
if grep -q "cat.*>.*\/etc\/network\/interfaces.d" "$(ls $WIFI_SCRIPT 2>/dev/null | head -1)"; then
|
||
if grep -q "mkdir -p /etc/network/interfaces.d" "$(ls $WIFI_SCRIPT 2>/dev/null | head -1)"; then
|
||
pass " WiFi: /etc/network/interfaces.d created before use"
|
||
else
|
||
error " WiFi: /etc/network/interfaces.d not created (will fail)"
|
||
fi
|
||
fi
|
||
|
||
# Check lighttpd directories
|
||
if grep -q "cat.*>.*lighttpd" "$(ls $WIFI_SCRIPT 2>/dev/null | head -1)"; then
|
||
if grep -q "mkdir -p.*lighttpd.*conf-" "$(ls $WIFI_SCRIPT 2>/dev/null | head -1)"; then
|
||
pass " WiFi: lighttpd config directories created"
|
||
else
|
||
warn " WiFi: lighttpd directories may not exist"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# ============================================================================
|
||
section "7. SOURCE FILE AVAILABILITY"
|
||
# ============================================================================
|
||
|
||
# Check if source files exist
|
||
for dir in app systemd scripts; do
|
||
if [ -d "$PROJECT_DIR/$dir" ]; then
|
||
pass "Source directory exists: $dir/"
|
||
else
|
||
error "Source directory missing: $dir/"
|
||
fi
|
||
done
|
||
|
||
if [ -f "$PROJECT_DIR/requirements.txt" ]; then
|
||
pass "requirements.txt exists"
|
||
else
|
||
error "requirements.txt missing"
|
||
fi
|
||
|
||
# ============================================================================
|
||
section "8. BUILD SCRIPT VALIDATION"
|
||
# ============================================================================
|
||
|
||
BUILD_SCRIPT="$PROJECT_DIR/build-image.sh"
|
||
if [ -f "$BUILD_SCRIPT" ]; then
|
||
pass "build-image.sh exists"
|
||
|
||
if [ -x "$BUILD_SCRIPT" ]; then
|
||
pass "build-image.sh is executable"
|
||
else
|
||
warn "build-image.sh is not executable"
|
||
fi
|
||
|
||
# Check if it uses our custom stages
|
||
if grep -q "stagePM3\|stageDangerousPi\|stage3\|stage4" "$BUILD_SCRIPT"; then
|
||
pass "build-image.sh references custom stages"
|
||
else
|
||
warn "build-image.sh may not reference custom stages"
|
||
fi
|
||
else
|
||
error "build-image.sh not found"
|
||
fi
|
||
|
||
# ============================================================================
|
||
section "9. PACKAGE NAME VALIDATION"
|
||
# ============================================================================
|
||
|
||
info "Validating package names against Debian repositories..."
|
||
|
||
# Create temporary container to query package database
|
||
TEMP_CONTAINER="preflight-pkg-check-$$"
|
||
docker run -d --name "$TEMP_CONTAINER" debian:trixie sleep 3600 > /dev/null 2>&1
|
||
docker exec "$TEMP_CONTAINER" apt-get update > /dev/null 2>&1
|
||
|
||
# Extract all package names from apt-get install commands
|
||
ALL_PACKAGES=$(grep -rh "apt-get install" "$PROJECT_DIR/pi-gen/stage"* 2>/dev/null | \
|
||
grep -v "^#" | \
|
||
sed 's/.*apt-get install//' | \
|
||
sed 's/-y//g; s/--no-install-recommends//g; s/--break-system-packages//g' | \
|
||
tr '\\' ' ' | \
|
||
tr '\n' ' ' | \
|
||
tr -s ' ' | \
|
||
grep -oE '[a-z0-9][a-z0-9+.-]+' | \
|
||
sort -u)
|
||
|
||
PACKAGE_ERRORS=0
|
||
for pkg in $ALL_PACKAGES; do
|
||
# Skip common flags, keywords, and commands
|
||
if echo "$pkg" | grep -qE '^(y|no|install|apt|get|update|upgrade|break|system|packages)$'; then
|
||
continue
|
||
fi
|
||
|
||
# Check if package exists in Debian repos
|
||
if docker exec "$TEMP_CONTAINER" apt-cache show "$pkg" > /dev/null 2>&1; then
|
||
pass " Package exists: $pkg"
|
||
else
|
||
error " Package NOT FOUND in Debian repos: $pkg"
|
||
info " Check for typos or hallucinated package names!"
|
||
((PACKAGE_ERRORS++))
|
||
fi
|
||
done
|
||
|
||
# Cleanup
|
||
docker rm -f "$TEMP_CONTAINER" > /dev/null 2>&1
|
||
|
||
if [ $PACKAGE_ERRORS -eq 0 ]; then
|
||
pass "All package names validated successfully"
|
||
else
|
||
error "Found $PACKAGE_ERRORS invalid package names"
|
||
info " Common mistakes: python-swig (should be: swig), libbluez-dev (should be: libbluetooth-dev)"
|
||
fi
|
||
|
||
# ============================================================================
|
||
section "10. FILE REFERENCE VALIDATION"
|
||
# ============================================================================
|
||
|
||
info "Checking for references to missing files..."
|
||
|
||
# Check for file copies in 00-run.sh scripts (outside chroot)
|
||
for script in "$PROJECT_DIR"/pi-gen/stage*/*/00-run.sh; do
|
||
if [ -f "$script" ]; then
|
||
STAGE_DIR=$(dirname "$script")
|
||
|
||
# Look for cp commands with source files
|
||
while read -r line; do
|
||
# Extract source path from cp commands
|
||
if echo "$line" | grep -q "^cp "; then
|
||
SRC=$(echo "$line" | awk '{print $2}' | sed 's/"//g')
|
||
|
||
# Skip if it's a flag, variable, or special path
|
||
if echo "$SRC" | grep -qE '^-|^\$|^\*|^/tmp|^/etc|^/var'; then
|
||
continue
|
||
fi
|
||
|
||
# Check if file exists relative to stage dir
|
||
if [ -f "$STAGE_DIR/$SRC" ] || [ -d "$STAGE_DIR/$SRC" ]; then
|
||
pass " Found: $SRC (in $(basename $(dirname "$script")))"
|
||
else
|
||
warn " Missing file reference: $SRC in $script"
|
||
fi
|
||
fi
|
||
done < <(grep -E "^cp " "$script" 2>/dev/null)
|
||
fi
|
||
done
|
||
|
||
# ============================================================================
|
||
section "11. SERVICE FILE SYNTAX VALIDATION"
|
||
# ============================================================================
|
||
|
||
info "Validating systemd service files..."
|
||
|
||
# Find all .service files in stage directories
|
||
for service_file in "$PROJECT_DIR"/pi-gen/stage*/*/*.service "$PROJECT_DIR"/systemd/*.service; do
|
||
if [ -f "$service_file" ]; then
|
||
BASENAME=$(basename "$service_file")
|
||
|
||
# Check for required sections
|
||
if grep -q "^\[Unit\]" "$service_file" && \
|
||
grep -q "^\[Service\]" "$service_file" && \
|
||
grep -q "^\[Install\]" "$service_file"; then
|
||
pass " Service file structure valid: $BASENAME"
|
||
else
|
||
error " Service file missing required sections: $BASENAME"
|
||
info " Required: [Unit], [Service], [Install]"
|
||
fi
|
||
|
||
# Check for ExecStart
|
||
if grep -q "^ExecStart=" "$service_file"; then
|
||
pass " Has ExecStart: $BASENAME"
|
||
else
|
||
error " Missing ExecStart in: $BASENAME"
|
||
fi
|
||
|
||
# Check for invalid __PLACEHOLDERS__ that weren't substituted
|
||
# Allow __DANGEROUS_PI_USER__ as it's intentionally substituted during build
|
||
UNSUBBED=$(grep "__.*__" "$service_file" 2>/dev/null | grep -v "__DANGEROUS_PI_USER__" || true)
|
||
if [ -n "$UNSUBBED" ]; then
|
||
warn " Found un-substituted placeholder in: $BASENAME"
|
||
echo "$UNSUBBED" | sed 's/^/ /'
|
||
fi
|
||
fi
|
||
done
|
||
|
||
# ============================================================================
|
||
section "12. ENVIRONMENT VARIABLE CHECKS"
|
||
# ============================================================================
|
||
|
||
info "Checking for undefined environment variables in scripts..."
|
||
|
||
for script in "$PROJECT_DIR"/pi-gen/stage*/*/[0-9][0-9]-*.sh; do
|
||
if [ -f "$script" ]; then
|
||
SCRIPT_NAME=$(basename "$script")
|
||
|
||
# Look for variable usage
|
||
USED_VARS=$(grep -oE '\$\{?[A-Z_][A-Z0-9_]*\}?' "$script" 2>/dev/null | \
|
||
sed 's/[${}]//g' | sort -u)
|
||
|
||
for var in $USED_VARS; do
|
||
# Check if variable is defined in script or is a known variable
|
||
if grep -q "^$var=" "$script" || \
|
||
grep -q "export $var=" "$script" || \
|
||
grep -q "$var=" "$script" || \
|
||
echo "$var" | grep -qE '^(ROOTFS_DIR|SCRIPT_DIR|DEFAULT_USER|DEFAULT_HOME|PATH|HOME|USER|HTTP|PM3_ROOT|BOOT_DIR|CONFIG_FILE|CMDLINE_FILE)$'; then
|
||
# Variable is defined, standard, or from external system (lighttpd config, PM3 build)
|
||
continue
|
||
else
|
||
warn " Potentially undefined variable: \$$var in $SCRIPT_NAME"
|
||
fi
|
||
done
|
||
fi
|
||
done
|
||
|
||
# ============================================================================
|
||
section "13. DISK SPACE CHECK"
|
||
# ============================================================================
|
||
|
||
info "Checking available disk space..."
|
||
|
||
REQUIRED_GB=15
|
||
AVAILABLE_KB=$(df /home/work/pi-gen-builder 2>/dev/null | tail -1 | awk '{print $4}')
|
||
AVAILABLE_GB=$((AVAILABLE_KB / 1024 / 1024))
|
||
|
||
if [ $AVAILABLE_GB -ge $REQUIRED_GB ]; then
|
||
pass "Sufficient disk space: ${AVAILABLE_GB}GB available (${REQUIRED_GB}GB required)"
|
||
else
|
||
error "Insufficient disk space: ${AVAILABLE_GB}GB available (${REQUIRED_GB}GB required)"
|
||
info " Pi-gen builds require ~15GB for image + cache"
|
||
info " Free up space or build will fail mid-download"
|
||
fi
|
||
|
||
# ============================================================================
|
||
section "14. NETWORK CONNECTIVITY CHECK"
|
||
# ============================================================================
|
||
|
||
info "Testing network connectivity to required repositories..."
|
||
|
||
# Test Debian repos
|
||
if curl -s --connect-timeout 5 http://deb.debian.org/debian/dists/trixie/Release > /dev/null 2>&1; then
|
||
pass "Can reach deb.debian.org"
|
||
else
|
||
error "Cannot reach deb.debian.org (Debian package repository)"
|
||
info " Check internet connection or firewall"
|
||
fi
|
||
|
||
# Test Raspberry Pi repos
|
||
if curl -s --connect-timeout 5 http://archive.raspberrypi.com/debian/dists/trixie/Release > /dev/null 2>&1; then
|
||
pass "Can reach archive.raspberrypi.com"
|
||
else
|
||
error "Cannot reach archive.raspberrypi.com (Raspberry Pi repository)"
|
||
fi
|
||
|
||
# Test GitHub (for PM3 clone)
|
||
if curl -s --connect-timeout 5 https://github.com > /dev/null 2>&1; then
|
||
pass "Can reach github.com"
|
||
else
|
||
error "Cannot reach github.com (needed for Proxmark3 clone)"
|
||
fi
|
||
|
||
# Test PM3 repo specifically
|
||
if git ls-remote https://github.com/RfidResearchGroup/proxmark3 > /dev/null 2>&1; then
|
||
pass "Proxmark3 repository is accessible"
|
||
else
|
||
error "Cannot access Proxmark3 repository"
|
||
info " URL: https://github.com/RfidResearchGroup/proxmark3"
|
||
fi
|
||
|
||
# ============================================================================
|
||
section "VALIDATION SUMMARY"
|
||
# ============================================================================
|
||
|
||
echo ""
|
||
echo "┌────────────────────────────────────────┐"
|
||
echo "│ VALIDATION RESULTS │"
|
||
echo "├────────────────────────────────────────┤"
|
||
printf "│ ${GREEN}Checks Passed:${NC} %-4d │\n" $CHECKS_PASSED
|
||
printf "│ ${YELLOW}Warnings:${NC} %-4d │\n" $WARNINGS
|
||
printf "│ ${RED}Errors:${NC} %-4d │\n" $ERRORS
|
||
echo "└────────────────────────────────────────┘"
|
||
echo ""
|
||
|
||
if [ $ERRORS -gt 0 ]; then
|
||
echo -e "${RED}╔════════════════════════════════════════════════════════════╗${NC}"
|
||
echo -e "${RED}║ BUILD WILL FAIL - FIX ERRORS BEFORE ATTEMPTING BUILD ║${NC}"
|
||
echo -e "${RED}╚════════════════════════════════════════════════════════════╝${NC}"
|
||
echo ""
|
||
echo "Do NOT start a build until all errors are fixed."
|
||
echo "Each error listed above will cause build failure."
|
||
exit 1
|
||
elif [ $WARNINGS -gt 0 ]; then
|
||
echo -e "${YELLOW}╔════════════════════════════════════════════════════════════╗${NC}"
|
||
echo -e "${YELLOW}║ WARNINGS DETECTED - REVIEW BEFORE BUILD ║${NC}"
|
||
echo -e "${YELLOW}╚════════════════════════════════════════════════════════════╝${NC}"
|
||
echo ""
|
||
echo "Warnings may indicate potential issues but won't necessarily fail the build."
|
||
exit 0
|
||
else
|
||
echo -e "${GREEN}╔════════════════════════════════════════════════════════════╗${NC}"
|
||
echo -e "${GREEN}║ ALL CHECKS PASSED - READY TO BUILD ║${NC}"
|
||
echo -e "${GREEN}╚════════════════════════════════════════════════════════════╝${NC}"
|
||
echo ""
|
||
echo "Build environment is validated. Safe to proceed with:"
|
||
echo " ./build-image.sh full"
|
||
exit 0
|
||
fi
|