feat(image): Add MOCHAbin USB live boot builder with LED kernel

- New build-mochabin-live-usb.sh for ARM64 live USB images
- Includes LED kernel support (IS31FL3199 driver)
- Recovery tools and diagnostics built-in
- extlinux boot configuration for Tow-Boot/U-Boot
- Network config for 10GbE + SFP+ + 4x GbE

Recovery documentation added to issue #39

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-05-07 10:42:59 +02:00
parent 627d521e8d
commit 144ee6288d

642
image/build-mochabin-live-usb.sh Executable file
View File

@ -0,0 +1,642 @@
#!/usr/bin/env bash
# ══════════════════════════════════════════════════════════════════
# SecuBox-DEB — build-mochabin-live-usb.sh v1.0
# Build bootable live USB for MOCHAbin with LED kernel support
# Usage: sudo bash image/build-mochabin-live-usb.sh [OPTIONS]
# ══════════════════════════════════════════════════════════════════
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_DIR="$(dirname "$SCRIPT_DIR")"
# ── Version & Build Info ──────────────────────────────────────────
SECUBOX_VERSION="2.0.0"
BUILD_DATE=$(date '+%Y-%m-%d')
BUILD_TIMESTAMP=$(date '+%Y-%m-%d %H:%M')
# ── Defaults ──────────────────────────────────────────────────────
BOARD="mochabin"
SUITE="bookworm"
IMG_SIZE="4G" # USB image size
OUT_DIR="${REPO_DIR}/output"
APT_MIRROR="http://deb.debian.org/debian"
APT_SECUBOX="https://apt.secubox.in"
USE_LOCAL_CACHE=0
SLIPSTREAM_DEBS=1
EMBED_IMAGE="" # Path to eMMC image to embed
NO_COMPRESS=0
INCLUDE_LED_KERNEL=1 # Include LED-enabled kernel
INCLUDE_RECOVERY=1 # Include recovery tools
RED='\033[0;31m'; CYAN='\033[0;36m'; GOLD='\033[0;33m'
GREEN='\033[0;32m'; NC='\033[0m'; BOLD='\033[1m'
log() { echo -e "${CYAN}[mochabin]${NC} $*"; }
ok() { echo -e "${GREEN}[ OK ]${NC} $*"; }
err() { echo -e "${RED}[ FAIL ]${NC} $*" >&2; exit 1; }
warn() { echo -e "${GOLD}[ WARN ]${NC} $*"; }
# ── Parse args ────────────────────────────────────────────────────
usage() {
cat << EOF
Usage: sudo bash build-mochabin-live-usb.sh [OPTIONS]
Build a bootable live USB image for MOCHAbin (Armada 7040) with:
- LED heartbeat support (IS31FL3199)
- Recovery tools for board recovery
- All SecuBox packages slipstreamed
OPTIONS:
--suite SUITE Debian suite (default: bookworm)
--out DIR Output directory (default: ./output)
--size SIZE USB image size (default: 4G)
--embed-image PATH Embed eMMC image for flashing (optional)
--local-cache Use local APT cache (apt-cacher-ng)
--no-slipstream Don't include local .deb packages
--no-compress Skip gzip compression
--no-led Don't include LED-enabled kernel
--no-recovery Don't include recovery tools
--help Show this help
FEATURES:
- Tow-Boot / U-Boot distroboot compatible
- LED kernel with IS31FL3199 driver
- Serial console on ttyS0 @ 115200
- Recovery tools for kwboot/XMODEM
- Network: 10GbE RJ45 + SFP+ + 4× GbE
EXAMPLES:
# Build with LED kernel and recovery
sudo bash build-mochabin-live-usb.sh
# Build with embedded eMMC image
sudo bash build-mochabin-live-usb.sh --embed-image output/secubox-mochabin.img.gz
OUTPUT:
output/secubox-mochabin-live-usb.img - Raw bootable image
output/secubox-mochabin-live-usb.img.gz - Compressed image
FLASH:
zcat output/secubox-mochabin-live-usb.img.gz | sudo dd of=/dev/sdX bs=4M status=progress
EOF
exit 0
}
while [[ $# -gt 0 ]]; do
case "$1" in
--suite) SUITE="$2"; shift 2 ;;
--out) OUT_DIR="$2"; shift 2 ;;
--size) IMG_SIZE="$2"; shift 2 ;;
--embed-image) EMBED_IMAGE="$2"; shift 2 ;;
--local-cache) USE_LOCAL_CACHE=1; shift ;;
--no-slipstream) SLIPSTREAM_DEBS=0; shift ;;
--no-compress) NO_COMPRESS=1; shift ;;
--no-led) INCLUDE_LED_KERNEL=0; shift ;;
--no-recovery) INCLUDE_RECOVERY=0; shift ;;
--help|-h) usage ;;
*) err "Unknown argument: $1" ;;
esac
done
# ── Checks ────────────────────────────────────────────────────────
[[ $EUID -ne 0 ]] && err "This script must be run as root (sudo)"
# Check for embedded image
if [[ -n "$EMBED_IMAGE" ]] && [[ ! -f "$EMBED_IMAGE" ]]; then
err "Embedded image not found: $EMBED_IMAGE"
fi
# Required tools
log "Checking dependencies..."
for cmd in debootstrap parted mkfs.fat mkfs.ext4 mksquashfs qemu-aarch64-static; do
command -v "$cmd" >/dev/null || {
warn "Missing: $cmd"
apt-get install -y -qq debootstrap squashfs-tools u-boot-tools qemu-user-static parted dosfstools 2>/dev/null || true
}
done
# Check again after install
for cmd in debootstrap parted mkfs.fat mkfs.ext4 mksquashfs; do
command -v "$cmd" >/dev/null || err "Missing required tool: $cmd"
done
# ── Local cache detection ─────────────────────────────────────
if [[ $USE_LOCAL_CACHE -eq 1 ]]; then
if curl -sf "http://127.0.0.1:3142" >/dev/null 2>&1; then
APT_MIRROR="http://127.0.0.1:3142/deb.debian.org/debian"
log "Using apt-cacher-ng"
fi
if curl -sf "http://127.0.0.1:8080/dists/${SUITE}/Release" >/dev/null 2>&1; then
APT_SECUBOX="http://127.0.0.1:8080"
log "Using local SecuBox repo"
fi
fi
# ── Setup ─────────────────────────────────────────────────────────
mkdir -p "$OUT_DIR"
WORK_DIR=$(mktemp -d /tmp/secubox-mochabin-live-XXXXXX)
ROOTFS="${WORK_DIR}/rootfs"
BOOT_DIR="${WORK_DIR}/boot"
IMG_FILE="${OUT_DIR}/secubox-mochabin-live-usb.img"
log "══════════════════════════════════════════════════════════"
log "Building SecuBox Live USB for MOCHAbin (Armada 7040)"
log "Suite : ${SUITE}"
log "Image : ${IMG_FILE}"
log "Size : ${IMG_SIZE}"
log "Work dir : ${WORK_DIR}"
log "LED kernel : $([[ $INCLUDE_LED_KERNEL -eq 1 ]] && echo "yes" || echo "no")"
log "Recovery : $([[ $INCLUDE_RECOVERY -eq 1 ]] && echo "yes" || echo "no")"
if [[ -n "$EMBED_IMAGE" ]]; then
log "Embed Image : $(basename "$EMBED_IMAGE")"
fi
log "══════════════════════════════════════════════════════════"
cleanup() {
log "Cleaning up..."
umount -lf "${ROOTFS}/proc" 2>/dev/null || true
umount -lf "${ROOTFS}/sys" 2>/dev/null || true
umount -lf "${ROOTFS}/dev/pts" 2>/dev/null || true
umount -lf "${ROOTFS}/dev" 2>/dev/null || true
umount -lf "${WORK_DIR}/mnt/"* 2>/dev/null || true
[[ -n "${LOOP:-}" ]] && losetup -d "${LOOP}" 2>/dev/null || true
if ! mount | grep -q "${WORK_DIR}"; then
rm -rf "${WORK_DIR}" 2>/dev/null || true
fi
}
trap cleanup EXIT
# ══════════════════════════════════════════════════════════════════
# Step 1: Debootstrap ARM64
# ══════════════════════════════════════════════════════════════════
log "1/8 Debootstrap ${SUITE} arm64..."
mkdir -p "${ROOTFS}"
# Core system packages
INCLUDE_PKGS="systemd,systemd-sysv,dbus,netplan.io,nftables,openssh-server,locales"
INCLUDE_PKGS+=",python3,python3-pip,nginx,curl,wget,ca-certificates,gnupg,console-setup"
INCLUDE_PKGS+=",iproute2,iputils-ping,ethtool,net-tools,wireguard-tools"
INCLUDE_PKGS+=",sudo,less,vim-tiny,logrotate,cron,rsync,jq,dnsmasq"
INCLUDE_PKGS+=",linux-image-arm64,live-boot,live-boot-initramfs-tools,live-config,live-config-systemd"
INCLUDE_PKGS+=",pciutils,usbutils,parted,dosfstools,e2fsprogs,lsb-release,gdisk"
INCLUDE_PKGS+=",pv,dialog,fonts-terminus,kbd,i2c-tools"
# Python dependencies for SecuBox modules
INCLUDE_PKGS+=",python3-fastapi,python3-uvicorn,python3-httpx,python3-psutil"
INCLUDE_PKGS+=",python3-aiosqlite,python3-jinja2,python3-jwt"
INCLUDE_PKGS+=",python3-aiofiles,python3-pil,python3-tomli,python3-pydantic"
INCLUDE_PKGS+=",python3-toml,python3-netifaces,python3-serial"
# Network and security tools
INCLUDE_PKGS+=",bridge-utils,dnsutils,iputils-arping,avahi-daemon,avahi-utils"
INCLUDE_PKGS+=",ieee-data,procps,openssl,haproxy,qrencode"
INCLUDE_PKGS+=",fonts-noto-color-emoji"
# Cross-architecture debootstrap with QEMU
debootstrap --arch=arm64 --foreign --include="${INCLUDE_PKGS}" \
"${SUITE}" "${ROOTFS}" "${APT_MIRROR}"
# Copy QEMU static binary for chroot
cp /usr/bin/qemu-aarch64-static "${ROOTFS}/usr/bin/"
# Complete second stage
chroot "${ROOTFS}" /debootstrap/debootstrap --second-stage
ok "Debootstrap complete"
# ══════════════════════════════════════════════════════════════════
# Step 2: Base configuration
# ══════════════════════════════════════════════════════════════════
log "2/8 System configuration..."
# Mount for chroot
mount -t proc proc "${ROOTFS}/proc"
mount -t sysfs sysfs "${ROOTFS}/sys"
mount --bind /dev "${ROOTFS}/dev"
# Configure APT sources
cat > "${ROOTFS}/etc/apt/sources.list" << SOURCES
deb ${APT_MIRROR} ${SUITE} main contrib non-free non-free-firmware
deb ${APT_MIRROR} ${SUITE}-updates main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security ${SUITE}-security main contrib non-free non-free-firmware
SOURCES
# Update and install critical packages
log "Installing critical packages..."
chroot "${ROOTFS}" bash -c "apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
parted e2fsprogs dosfstools gdisk rsync findutils \
iproute2 iputils-ping net-tools bridge-utils \
systemd-resolved netplan.io device-tree-compiler \
2>&1" | tail -20 || warn "Some packages may have failed"
# Python crypto packages
chroot "${ROOTFS}" bash -c "DEBIAN_FRONTEND=noninteractive apt-get install -y -q \
python3-cryptography python3-jose python3-zmq 2>&1" | tail -10 || warn "Some Python packages not installed"
# Hostname
echo "secubox-mochabin" > "${ROOTFS}/etc/hostname"
cat > "${ROOTFS}/etc/hosts" << 'EOF'
127.0.0.1 localhost secubox-mochabin secubox
::1 localhost ip6-localhost ip6-loopback
EOF
# Root password: secubox
chroot "${ROOTFS}" bash -c 'echo "root:secubox" | chpasswd'
# Timezone
echo "Europe/Paris" > "${ROOTFS}/etc/timezone"
chroot "${ROOTFS}" dpkg-reconfigure -f noninteractive tzdata 2>/dev/null || true
# Locale
chroot "${ROOTFS}" bash -c "locale-gen en_US.UTF-8 fr_FR.UTF-8 || true"
echo 'LANG=fr_FR.UTF-8' > "${ROOTFS}/etc/default/locale"
# Console font
mkdir -p "${ROOTFS}/etc/console-setup"
cat > "${ROOTFS}/etc/default/console-setup" <<EOF
ACTIVE_CONSOLES="/dev/tty[1-6]"
CHARMAP="UTF-8"
CODESET="Uni2"
FONTFACE="Terminus"
FONTSIZE="16"
EOF
cat > "${ROOTFS}/etc/vconsole.conf" <<EOF
KEYMAP=fr
FONT=ter-v16n
EOF
# Serial console on ttyS0 (MOCHAbin uses ttyS0)
mkdir -p "${ROOTFS}/etc/systemd/system/serial-getty@ttyS0.service.d"
cat > "${ROOTFS}/etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf" << 'EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty -o '-p -f -- \\u' --autologin root --noclear %I 115200 linux
EOF
chroot "${ROOTFS}" systemctl enable serial-getty@ttyS0.service 2>/dev/null || true
ok "Base configuration complete"
# ══════════════════════════════════════════════════════════════════
# Step 3: Network configuration (MOCHAbin specific)
# ══════════════════════════════════════════════════════════════════
log "3/8 Network configuration..."
mkdir -p "${ROOTFS}/etc/netplan"
cat > "${ROOTFS}/etc/netplan/00-secubox-mochabin.yaml" << 'NETPLAN'
# MOCHAbin Network Configuration
# Interfaces: eth0 (10G RJ45), eth1-4 (GbE), eth5-6 (SFP+)
network:
version: 2
renderer: networkd
ethernets:
# 10G RJ45 WAN
eth0:
dhcp4: true
dhcp6: false
optional: true
# GbE LAN ports (bridged)
eth1:
dhcp4: false
optional: true
eth2:
dhcp4: false
optional: true
eth3:
dhcp4: false
optional: true
eth4:
dhcp4: false
optional: true
# SFP+ ports (optional)
eth5:
dhcp4: false
optional: true
eth6:
dhcp4: false
optional: true
bridges:
br-lan:
interfaces: [eth1, eth2, eth3, eth4]
addresses: [192.168.1.1/24]
dhcp4: false
parameters:
stp: false
forward-delay: 0
NETPLAN
ok "Network configured"
# ══════════════════════════════════════════════════════════════════
# Step 4: LED kernel and heartbeat
# ══════════════════════════════════════════════════════════════════
if [[ $INCLUDE_LED_KERNEL -eq 1 ]]; then
log "4/8 Installing LED support..."
# Copy LED DTS overlay
LED_DTS="${REPO_DIR}/packages/secubox-led-heartbeat/boot/overlays/secubox-leds.dts"
if [[ -f "$LED_DTS" ]]; then
mkdir -p "${ROOTFS}/usr/share/secubox/overlays"
cp "$LED_DTS" "${ROOTFS}/usr/share/secubox/overlays/"
fi
# Copy LED heartbeat script
LED_SCRIPT="${REPO_DIR}/packages/secubox-led-heartbeat/usr/sbin/secubox-led-heartbeat-bash"
if [[ -f "$LED_SCRIPT" ]]; then
cp "$LED_SCRIPT" "${ROOTFS}/usr/sbin/secubox-led-heartbeat"
chmod +x "${ROOTFS}/usr/sbin/secubox-led-heartbeat"
fi
# LED config
mkdir -p "${ROOTFS}/etc/secubox"
cat > "${ROOTFS}/etc/secubox/leds.toml" << 'TOML'
# SecuBox LED Configuration
# MOCHAbin IS31FL3199 LED controller
[general]
enabled = true
i2c_bus = 1
i2c_addr = 0x64
gpio_sdb = 94
[health]
led = 1
green_threshold = 80
yellow_threshold = 50
[security]
led = 2
# Indicates firewall/IDS status
[capacity]
led = 3
# Shows disk/memory usage
TOML
# LED module load
mkdir -p "${ROOTFS}/etc/modules-load.d"
cat > "${ROOTFS}/etc/modules-load.d/secubox-leds.conf" << 'EOF'
# SecuBox LED drivers
leds_is31fl319x
ledtrig-heartbeat
i2c-mv64xxx
EOF
# LED systemd service
mkdir -p "${ROOTFS}/etc/systemd/system"
cat > "${ROOTFS}/etc/systemd/system/secubox-led-heartbeat.service" << 'SERVICE'
[Unit]
Description=SecuBox LED Heartbeat
After=local-fs.target
Wants=local-fs.target
[Service]
Type=simple
ExecStart=/usr/sbin/secubox-led-heartbeat
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
SERVICE
chroot "${ROOTFS}" systemctl enable secubox-led-heartbeat.service 2>/dev/null || true
ok "LED support installed"
else
log "4/8 Skipping LED support (--no-led)"
fi
# ══════════════════════════════════════════════════════════════════
# Step 5: Recovery tools
# ══════════════════════════════════════════════════════════════════
if [[ $INCLUDE_RECOVERY -eq 1 ]]; then
log "5/8 Installing recovery tools..."
mkdir -p "${ROOTFS}/srv/secubox-recovery/boards/mochabin"
mkdir -p "${ROOTFS}/srv/secubox-recovery/tools"
# Recovery info
cat > "${ROOTFS}/srv/secubox-recovery/boards/mochabin/info.json" << 'JSON'
{
"board": "MOCHAbin",
"soc": "Armada 7040",
"cores": 4,
"arch": "cortex-a72",
"boot_tool": "mvebu64boot",
"uart": "/dev/ttyUSB0",
"baud": 115200,
"storage": ["emmc", "sata", "usb"],
"led_driver": "is31fl319x",
"led_i2c": "1-0064"
}
JSON
# Diagnostic script
cat > "${ROOTFS}/usr/sbin/secubox-diag" << 'DIAG'
#!/bin/bash
# SecuBox MOCHAbin Diagnostic Script
set -euo pipefail
echo "═══════════════════════════════════════════════════════"
echo "SecuBox MOCHAbin Diagnostics"
echo "═══════════════════════════════════════════════════════"
echo -e "\n── System ──"
uname -a
cat /etc/os-release | grep PRETTY_NAME
echo -e "\n── Hardware ──"
cat /proc/cpuinfo | grep -E "^(model name|Hardware)" | head -2
free -h | grep Mem
echo -e "\n── Network Interfaces ──"
ip -br link show
echo -e "\n── I2C Devices ──"
for bus in /dev/i2c-*; do
if [[ -e "$bus" ]]; then
echo "Bus: $bus"
i2cdetect -y "${bus##*-}" 2>/dev/null || echo " (scan failed)"
fi
done
echo -e "\n── LED Status ──"
if [[ -d /sys/class/leds ]]; then
for led in /sys/class/leds/*/brightness; do
name=$(dirname "$led" | xargs basename)
val=$(cat "$led" 2>/dev/null || echo "?")
echo " $name: $val"
done
else
echo " No LEDs found"
fi
echo -e "\n── Storage ──"
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT 2>/dev/null || fdisk -l 2>/dev/null | head -20
echo "═══════════════════════════════════════════════════════"
DIAG
chmod +x "${ROOTFS}/usr/sbin/secubox-diag"
ok "Recovery tools installed"
else
log "5/8 Skipping recovery tools (--no-recovery)"
fi
# ══════════════════════════════════════════════════════════════════
# Step 6: Slipstream SecuBox packages
# ══════════════════════════════════════════════════════════════════
if [[ $SLIPSTREAM_DEBS -eq 1 ]]; then
log "6/8 Slipstreaming SecuBox packages..."
DEBS_DIR="${OUT_DIR}/debs"
if [[ -d "$DEBS_DIR" ]] && compgen -G "${DEBS_DIR}/*.deb" > /dev/null; then
mkdir -p "${ROOTFS}/tmp/debs"
cp "${DEBS_DIR}"/*.deb "${ROOTFS}/tmp/debs/" 2>/dev/null || true
DEB_COUNT=$(ls -1 "${ROOTFS}/tmp/debs/"*.deb 2>/dev/null | wc -l)
log "Found $DEB_COUNT .deb packages"
chroot "${ROOTFS}" bash -c "dpkg -i /tmp/debs/*.deb 2>/dev/null || apt-get -f install -y" || warn "Some packages failed"
rm -rf "${ROOTFS}/tmp/debs"
ok "Packages slipstreamed"
else
warn "No .deb packages found in $DEBS_DIR"
fi
else
log "6/8 Skipping package slipstream (--no-slipstream)"
fi
# ══════════════════════════════════════════════════════════════════
# Step 7: Create image
# ══════════════════════════════════════════════════════════════════
log "7/8 Creating bootable image..."
# Cleanup chroot mounts before image creation
umount -lf "${ROOTFS}/proc" 2>/dev/null || true
umount -lf "${ROOTFS}/sys" 2>/dev/null || true
umount -lf "${ROOTFS}/dev" 2>/dev/null || true
# Create disk image
truncate -s "$IMG_SIZE" "$IMG_FILE"
LOOP=$(losetup -f --show "$IMG_FILE")
# Partition: ESP (128M) + rootfs (rest)
parted -s "$LOOP" mklabel gpt
parted -s "$LOOP" mkpart ESP fat32 1MiB 129MiB
parted -s "$LOOP" set 1 esp on
parted -s "$LOOP" mkpart rootfs ext4 129MiB 100%
# Rescan partitions
partprobe "$LOOP"
sleep 1
# Get partition devices
ESP_PART="${LOOP}p1"
ROOT_PART="${LOOP}p2"
# Fallback for different naming
[[ -b "$ESP_PART" ]] || ESP_PART="${LOOP}p1"
[[ -b "$ROOT_PART" ]] || ROOT_PART="${LOOP}p2"
# Format
mkfs.fat -F 32 -n ESP "$ESP_PART"
mkfs.ext4 -L rootfs -F "$ROOT_PART"
# Mount and copy
mkdir -p "${WORK_DIR}/mnt/rootfs" "${WORK_DIR}/mnt/esp"
mount "$ROOT_PART" "${WORK_DIR}/mnt/rootfs"
mount "$ESP_PART" "${WORK_DIR}/mnt/esp"
# Copy rootfs
rsync -aHAX --info=progress2 "${ROOTFS}/" "${WORK_DIR}/mnt/rootfs/"
# Setup boot partition
mkdir -p "${WORK_DIR}/mnt/esp/extlinux"
# Copy MOCHAbin extlinux config
EXTLINUX_CONF="${REPO_DIR}/board/mochabin/extlinux/extlinux.conf"
if [[ -f "$EXTLINUX_CONF" ]]; then
cp "$EXTLINUX_CONF" "${WORK_DIR}/mnt/esp/extlinux/"
# Adjust for USB boot (root=/dev/sda2 or UUID)
ROOT_UUID=$(blkid -s UUID -o value "$ROOT_PART")
sed -i "s|root=/dev/mmcblk0p2|root=UUID=${ROOT_UUID}|g" "${WORK_DIR}/mnt/esp/extlinux/extlinux.conf"
fi
# Copy kernel and DTB to ESP
KERNEL_SRC="${WORK_DIR}/mnt/rootfs/boot"
if [[ -f "${KERNEL_SRC}/vmlinuz" ]]; then
cp "${KERNEL_SRC}/vmlinuz" "${WORK_DIR}/mnt/esp/Image"
fi
if [[ -f "${KERNEL_SRC}/initrd.img" ]]; then
cp "${KERNEL_SRC}/initrd.img" "${WORK_DIR}/mnt/esp/"
fi
# Copy DTB
mkdir -p "${WORK_DIR}/mnt/esp/dtbs/marvell"
if [[ -d "${KERNEL_SRC}/dtbs" ]]; then
cp -r "${KERNEL_SRC}/dtbs/"* "${WORK_DIR}/mnt/esp/dtbs/" 2>/dev/null || true
fi
# Try standard Debian location
if [[ -d "${WORK_DIR}/mnt/rootfs/usr/lib/linux-image-"* ]]; then
DTB_DIR=$(ls -1d "${WORK_DIR}/mnt/rootfs/usr/lib/linux-image-"* | head -1)
if [[ -f "${DTB_DIR}/marvell/armada-7040-mochabin.dtb" ]]; then
cp "${DTB_DIR}/marvell/armada-7040-mochabin.dtb" "${WORK_DIR}/mnt/esp/dtbs/marvell/"
fi
fi
# Create fstab
cat > "${WORK_DIR}/mnt/rootfs/etc/fstab" << FSTAB
# SecuBox MOCHAbin Live USB
UUID=${ROOT_UUID} / ext4 errors=remount-ro 0 1
LABEL=ESP /boot vfat defaults 0 2
FSTAB
# Unmount
sync
umount "${WORK_DIR}/mnt/esp"
umount "${WORK_DIR}/mnt/rootfs"
losetup -d "$LOOP"
LOOP=""
ok "Image created: $IMG_FILE"
# ══════════════════════════════════════════════════════════════════
# Step 8: Compress
# ══════════════════════════════════════════════════════════════════
if [[ $NO_COMPRESS -eq 0 ]]; then
log "8/8 Compressing image..."
gzip -f -k "$IMG_FILE"
ok "Compressed: ${IMG_FILE}.gz"
else
log "8/8 Skipping compression (--no-compress)"
fi
# ══════════════════════════════════════════════════════════════════
# Done
# ══════════════════════════════════════════════════════════════════
IMG_SIZE_MB=$(du -m "$IMG_FILE" | cut -f1)
log ""
log "══════════════════════════════════════════════════════════"
log "Build complete!"
log "══════════════════════════════════════════════════════════"
log "Image : $IMG_FILE ($IMG_SIZE_MB MB)"
[[ $NO_COMPRESS -eq 0 ]] && log "Compressed : ${IMG_FILE}.gz"
log ""
log "Flash to USB:"
log " zcat ${IMG_FILE}.gz | sudo dd of=/dev/sdX bs=4M status=progress"
log ""
log "Boot:"
log " 1. Insert USB into MOCHAbin"
log " 2. Enter U-Boot prompt"
log " 3. run usb_boot (or: usb start; load usb 0:1 ...)"
log ""
log "Default credentials:"
log " User: root"
log " Pass: secubox"
log "══════════════════════════════════════════════════════════"