fix(build): Add timeouts to prevent build script hangs

- Add 5 min timeout per package in dpkg-buildpackage calls
- Add 10-20 min timeout for QEMU chroot apt operations
- Add 45 min timeout for sub-script execution
- Add 15 min timeout with retries for wget downloads
- Fix pipe to tail pattern that swallowed exit codes
- Add progress logging for QEMU package installation
- Use writable log directory (output/logs) instead of /tmp
- Add --verbose flag to build-eye-remote-full.sh
- Export VERBOSE for sub-scripts

Fixes hangs caused by:
- dpkg-buildpackage | tail -5 buffering issues
- QEMU chroot apt-get with no timeout
- Network operations with no timeout

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-04-26 19:04:20 +02:00
parent ed25dde74e
commit fd86a6709f
5 changed files with 113 additions and 42 deletions

View File

@ -54,6 +54,7 @@ SKIP_EBIN=0
SKIP_RPIZ=0
WIFI_SSID=""
WIFI_PSK=""
VERBOSE=0
# ── Usage ─────────────────────────────────────────────────────────────────────
usage() {
@ -136,11 +137,15 @@ while [[ $# -gt 0 ]]; do
IFS=':' read -r WIFI_SSID WIFI_PSK <<< "$2"
shift 2
;;
--verbose|-v) VERBOSE=1; shift ;;
--help|-h) usage ;;
*) err "Unknown option: $1" ;;
esac
done
# Export VERBOSE for sub-scripts
export VERBOSE
# ── Prerequisites ─────────────────────────────────────────────────────────────
[[ $EUID -ne 0 ]] && err "This script must be run as root (sudo)"
@ -206,9 +211,11 @@ build_debs() {
log "Building SecuBox packages..."
# Use existing build-all.sh script
# Use existing build-all.sh script (with 30 min timeout)
if [[ -f "${SCRIPT_DIR}/scripts/build-all.sh" ]]; then
bash "${SCRIPT_DIR}/scripts/build-all.sh" "$DEBS_DIR"
if ! timeout --kill-after=60s 1800s bash "${SCRIPT_DIR}/scripts/build-all.sh" "$DEBS_DIR"; then
warn "build-all.sh timed out or failed, trying inline build..."
fi
else
# Inline build
local pkg_dirs
@ -228,11 +235,12 @@ build_debs() {
log "[$count/$total] $pkg"
cd "$pkg_dir"
if dpkg-buildpackage -us -uc -b > /tmp/build-$pkg.log 2>&1; then
# 5 min timeout per package
if timeout --kill-after=30s 300s dpkg-buildpackage -us -uc -b > /tmp/build-$pkg.log 2>&1; then
mv ../*.deb "$DEBS_DIR/" 2>/dev/null || true
rm -f ../*.buildinfo ../*.changes 2>/dev/null || true
else
warn "$pkg failed (see /tmp/build-$pkg.log)"
warn "$pkg failed or timed out (see /tmp/build-$pkg.log)"
failed=$((failed + 1))
fi
cd "$SCRIPT_DIR"
@ -284,13 +292,16 @@ build_ebin() {
fi
fi
# Use build-storage-img.sh if available
# Use build-storage-img.sh if available (with 30 min timeout)
if [[ -f "${SCRIPT_DIR}/remote-ui/round/build-storage-img.sh" ]]; then
log "Building ESPRESSObin storage image with slipstreamed modules..."
bash "${SCRIPT_DIR}/remote-ui/round/build-storage-img.sh" \
log "This may take 20-30 minutes under QEMU emulation. Timeout: 45 min."
if ! timeout --kill-after=60s 2700s bash "${SCRIPT_DIR}/remote-ui/round/build-storage-img.sh" \
--source "$EBIN_SOURCE" \
--output "$EBIN_STORAGE_IMG" \
--debs "$DEBS_DIR"
--debs "$DEBS_DIR"; then
err "build-storage-img.sh failed or timed out"
fi
else
err "build-storage-img.sh not found"
fi
@ -313,13 +324,16 @@ download_rpios() {
return 0
fi
log "Downloading RPi OS Lite..."
wget -q --show-progress -O "$target" "$url" || {
log "Downloading RPi OS Lite (timeout: 15 min)..."
# 15 min timeout for download, with connection timeout of 30s
if ! timeout --kill-after=30s 900s wget --timeout=30 --tries=3 -q --show-progress -O "$target" "$url"; then
warn "Download failed, trying alternative URL..."
# Try alternative
url="https://downloads.raspberrypi.org/raspios_lite_armhf_latest"
wget -q --show-progress -O "$target" "$url" || err "Failed to download RPi OS"
}
if ! timeout --kill-after=30s 900s wget --timeout=30 --tries=3 -q --show-progress -O "$target" "$url"; then
err "Failed to download RPi OS (check network connection)"
fi
fi
RPIZ_SOURCE="$target"
ok "Downloaded: $target"
@ -369,19 +383,22 @@ build_rpiz() {
log "Building Pi Zero SD image with embedded ESPRESSObin storage..."
# Use build-eye-remote-image.sh
# Use build-eye-remote-image.sh (with 30 min timeout for QEMU operations)
if [[ -f "${SCRIPT_DIR}/remote-ui/round/build-eye-remote-image.sh" ]]; then
local wifi_args=""
if [[ -n "$WIFI_SSID" ]]; then
wifi_args="-s $WIFI_SSID -p $WIFI_PSK"
fi
log "Building Pi Zero image with QEMU emulation. Timeout: 45 min."
# Build the base image
bash "${SCRIPT_DIR}/remote-ui/round/build-eye-remote-image.sh" \
if ! timeout --kill-after=60s 2700s bash "${SCRIPT_DIR}/remote-ui/round/build-eye-remote-image.sh" \
-i "$RPIZ_SOURCE" \
-o "$OUTPUT_DIR" \
$wifi_args \
--framebuffer
--framebuffer; then
err "build-eye-remote-image.sh failed or timed out"
fi
# Find the generated image
local built_img

View File

@ -453,7 +453,7 @@ info "Packages: ${PACKAGES[*]}"
# Create package list file (dynamically based on BUILD_MODE)
printf "%s\n" "${PACKAGES[@]}" > "$ROOT_MNT/tmp/package-list.txt"
# Create install script
# Create install script with progress output
cat > "$ROOT_MNT/tmp/install-packages.sh" << 'INSTALLSCRIPT'
#!/bin/bash
set -e
@ -461,17 +461,32 @@ set -e
export DEBIAN_FRONTEND=noninteractive
export LC_ALL=C
echo "=== Updating APT ==="
apt-get update -qq
echo "=== [1/5] Updating APT (this may take a few minutes under QEMU) ==="
apt-get update -q || { echo "APT update failed"; exit 1; }
echo "=== Installing packages ==="
# Read packages from file and install with --no-install-recommends
xargs -a /tmp/package-list.txt apt-get install -y -qq --no-install-recommends
echo "=== [2/5] Reading package list ==="
PACKAGES=$(cat /tmp/package-list.txt | tr '\n' ' ')
echo "Packages to install: $PACKAGES"
echo "=== Enabling pigpiod ==="
echo "=== [3/5] Installing packages one by one (QEMU is slow, be patient) ==="
INSTALLED=0
FAILED=0
for pkg in $PACKAGES; do
echo " -> Installing: $pkg"
if apt-get install -y -qq --no-install-recommends "$pkg" 2>/dev/null; then
echo " OK: $pkg"
INSTALLED=$((INSTALLED + 1))
else
echo " WARN: $pkg failed (may be optional)"
FAILED=$((FAILED + 1))
fi
done
echo " Installed: $INSTALLED, Failed: $FAILED"
echo "=== [4/5] Enabling pigpiod ==="
systemctl enable pigpiod || true
echo "=== Cleaning APT cache ==="
echo "=== [5/5] Cleaning APT cache ==="
apt-get clean
rm -rf /var/lib/apt/lists/*
rm -f /tmp/package-list.txt
@ -480,8 +495,18 @@ echo "=== Package installation complete ==="
INSTALLSCRIPT
chmod +x "$ROOT_MNT/tmp/install-packages.sh"
# Run install in chroot
chroot "$ROOT_MNT" /tmp/install-packages.sh
# Run install in chroot with timeout (20 minutes for QEMU ARM emulation)
log "Running package installation in QEMU chroot (this takes 10-20 minutes)..."
log "Progress will be shown below. If it hangs > 20min, check network/DNS."
CHROOT_LOG="/tmp/eye-remote-chroot-install.log"
if timeout --kill-after=60s 1200s chroot "$ROOT_MNT" /tmp/install-packages.sh 2>&1 | tee "$CHROOT_LOG"; then
log "Package installation completed successfully"
else
err "Package installation failed or timed out (see $CHROOT_LOG)"
tail -20 "$CHROOT_LOG" || true
exit 1
fi
# Remove policy
rm -f "$ROOT_MNT/usr/sbin/policy-rc.d"
@ -683,7 +708,9 @@ systemctl enable lightdm 2>/dev/null || true
systemctl enable nginx 2>/dev/null || true
USERSCRIPT
chmod +x "$ROOT_MNT/tmp/setup-user.sh"
chroot "$ROOT_MNT" /tmp/setup-user.sh
if ! timeout --kill-after=10s 120s chroot "$ROOT_MNT" /tmp/setup-user.sh 2>&1; then
warn "setup-user.sh failed or timed out (non-fatal)"
fi
# LightDM autologin
mkdir -p "$ROOT_MNT/etc/lightdm/lightdm.conf.d"
@ -737,7 +764,7 @@ XINITRC
chmod +x "$ROOT_MNT/home/secubox/.xinitrc"
# Fix ownership
chroot "$ROOT_MNT" chown -R secubox:secubox /home/secubox
timeout --kill-after=5s 30s chroot "$ROOT_MNT" chown -R secubox:secubox /home/secubox 2>/dev/null || true
# ═══════════════════════════════════════════════════════════════════════════════
# CONFIGURE NGINX (browser mode only)
@ -802,7 +829,7 @@ if [[ -n "$SSH_PUBKEY" && -f "$SSH_PUBKEY" ]]; then
cp "$SSH_PUBKEY" "$ROOT_MNT/home/pi/.ssh/authorized_keys"
chmod 700 "$ROOT_MNT/home/pi/.ssh"
chmod 600 "$ROOT_MNT/home/pi/.ssh/authorized_keys"
chroot "$ROOT_MNT" chown -R pi:pi /home/pi/.ssh
timeout --kill-after=5s 30s chroot "$ROOT_MNT" chown -R pi:pi /home/pi/.ssh 2>/dev/null || true
fi
# ═══════════════════════════════════════════════════════════════════════════════

View File

@ -203,35 +203,50 @@ done
log "Installing ${COPIED_COUNT} compatible packages..."
# Update apt cache first
log "Updating apt cache..."
chroot "${TARGET_MOUNT}" apt-get update -qq 2>&1 | tail -5 || true
# Timeouts for QEMU chroot operations (very slow under emulation)
CHROOT_TIMEOUT="timeout --kill-after=30s 600s" # 10 min timeout
# Update apt cache first (with timeout)
log "Updating apt cache (QEMU, may take several minutes)..."
if ! $CHROOT_TIMEOUT chroot "${TARGET_MOUNT}" apt-get update -qq > /tmp/apt-update.log 2>&1; then
warn "apt-get update failed or timed out (see /tmp/apt-update.log)"
tail -5 /tmp/apt-update.log 2>/dev/null | sed 's/^/ /' || true
fi
# Install secubox-core first (with dependencies)
if ls "${DEBS_TMP}"/secubox-core_*.deb >/dev/null 2>&1; then
log "Installing secubox-core with dependencies..."
CORE_DEB=$(ls "${DEBS_TMP}"/secubox-core_*.deb | head -1)
chroot "${TARGET_MOUNT}" apt-get install -y "/tmp/secubox-debs/$(basename $CORE_DEB)" 2>&1 | tail -10 || warn "core install warnings"
if ! $CHROOT_TIMEOUT chroot "${TARGET_MOUNT}" apt-get install -y "/tmp/secubox-debs/$(basename "$CORE_DEB")" > /tmp/core-install.log 2>&1; then
warn "secubox-core install warnings (see /tmp/core-install.log)"
tail -5 /tmp/core-install.log 2>/dev/null | sed 's/^/ /' || true
fi
fi
# Install all other packages using apt (handles dependencies)
log "Installing remaining packages..."
PKG_COUNT=0
for deb in "${DEBS_TMP}"/secubox-*.deb; do
[[ -f "$deb" ]] || continue
PKG_NAME=$(dpkg-deb -f "$deb" Package 2>/dev/null)
PKG_COUNT=$((PKG_COUNT + 1))
# Skip if already installed
if chroot "${TARGET_MOUNT}" dpkg -l "$PKG_NAME" 2>/dev/null | grep -q "^ii"; then
continue
fi
# Try to install with apt
chroot "${TARGET_MOUNT}" apt-get install -y "/tmp/secubox-debs/$(basename $deb)" 2>&1 | \
grep -E "^(Setting up|is already)" || true
log " [$PKG_COUNT] Installing $PKG_NAME..."
# 3 min timeout per package
if ! timeout --kill-after=10s 180s chroot "${TARGET_MOUNT}" apt-get install -y \
"/tmp/secubox-debs/$(basename "$deb")" > "/tmp/install-${PKG_NAME}.log" 2>&1; then
warn " $PKG_NAME failed (see /tmp/install-${PKG_NAME}.log)"
fi
done
# Fix any remaining broken dependencies
chroot "${TARGET_MOUNT}" apt-get -f install -y --fix-broken 2>&1 | tail -5 || true
log "Fixing broken dependencies..."
$CHROOT_TIMEOUT chroot "${TARGET_MOUNT}" apt-get -f install -y --fix-broken > /tmp/fix-broken.log 2>&1 || true
# Count installed
INSTALLED=$(chroot "${TARGET_MOUNT}" dpkg -l 2>/dev/null | grep "^ii.*secubox" | wc -l)

View File

@ -45,14 +45,15 @@ for pkg_dir in $PACKAGES; do
# Clean previous build
rm -rf debian/.debhelper debian/"$pkg" 2>/dev/null || true
# Build
if dpkg-buildpackage -us -uc -b > /tmp/build-$pkg.log 2>&1; then
# Build with 5 minute timeout per package
if timeout --kill-after=30s 300s dpkg-buildpackage -us -uc -b > /tmp/build-$pkg.log 2>&1; then
# Move .deb files
mv ../*.deb "$OUTPUT_DIR/" 2>/dev/null || true
rm -f ../*.buildinfo ../*.changes 2>/dev/null || true
ok "$pkg"
else
err "$pkg - build failed (see /tmp/build-$pkg.log)"
err "$pkg - build failed or timed out (see /tmp/build-$pkg.log)"
tail -5 /tmp/build-$pkg.log 2>/dev/null | sed 's/^/ /' || true
FAILED=$((FAILED + 1))
fi

View File

@ -98,15 +98,24 @@ for PKG in "${PACKAGES[@]}"; do
# Rendre rules exécutable
chmod +x debian/rules 2>/dev/null || true
# Build le package
# Build le package with timeout and proper exit code handling
# Use a writable log directory (avoid /tmp permission issues from previous root runs)
LOG_DIR="${REPO_DIR}/output/logs"
mkdir -p "$LOG_DIR" 2>/dev/null || LOG_DIR="/tmp/secubox-build-$$"
mkdir -p "$LOG_DIR" 2>/dev/null || true
BUILD_LOG="${LOG_DIR}/build-${PKG}.log"
BUILD_OK=0
# Use timeout to prevent infinite hangs (5 minutes per package)
TIMEOUT_CMD="timeout --kill-after=30s 300s"
if [[ "$ARCH" == "arm64" ]] && [[ "$(uname -m)" != "aarch64" ]]; then
# Cross-compile pour arm64
if dpkg-buildpackage -a arm64 --host-arch arm64 -us -uc -b 2>&1 | tail -5; then
if $TIMEOUT_CMD dpkg-buildpackage -a arm64 --host-arch arm64 -us -uc -b > "$BUILD_LOG" 2>&1; then
BUILD_OK=1
fi
else
if dpkg-buildpackage -us -uc -b 2>&1 | tail -5; then
if $TIMEOUT_CMD dpkg-buildpackage -us -uc -b > "$BUILD_LOG" 2>&1; then
BUILD_OK=1
fi
fi
@ -115,7 +124,9 @@ for PKG in "${PACKAGES[@]}"; do
ok "${PKG} built"
((SUCCESS++)) || true
else
err "${PKG} FAILED"
# Show last 10 lines of log for debugging
err "${PKG} FAILED (see $BUILD_LOG)"
tail -10 "$BUILD_LOG" 2>/dev/null | sed 's/^/ /' || true
((FAILED++)) || true
fi
done