feat(isobuild): add multi-architecture build and Raspberry Pi support in installer and build tooling

This commit is contained in:
2026-01-13 07:55:09 +00:00
parent 2d4846cfed
commit 2c5ea744f1
13 changed files with 1227 additions and 350 deletions

View File

@@ -1,33 +1,52 @@
# EcoOS ISO Builder
# Build from eco_os directory:
# docker build -t ecoos-builder -f isobuild/Dockerfile .
# docker build --build-arg TARGET_ARCH=amd64 -t ecoos-builder -f isobuild/Dockerfile .
# docker run --privileged -v $(pwd)/isobuild/output:/output ecoos-builder
#
# Supported architectures: amd64, arm64, rpi
FROM ubuntu:24.04
ARG TARGET_ARCH=amd64
ENV TARGET_ARCH=${TARGET_ARCH}
ENV DEBIAN_FRONTEND=noninteractive
# Install build dependencies
# Install common build dependencies
RUN apt-get update && apt-get install -y \
live-build \
debootstrap \
xorriso \
squashfs-tools \
grub-efi-amd64-bin \
grub-efi-amd64-signed \
grub-pc-bin \
shim-signed \
mtools \
dosfstools \
syslinux-utils \
syslinux \
syslinux-common \
isolinux \
curl \
unzip \
git \
&& rm -rf /var/lib/apt/lists/* \
&& ln -sf /usr/bin/isohybrid /usr/local/bin/isohybrid 2>/dev/null || true
parted \
fdisk \
e2fsprogs \
&& rm -rf /var/lib/apt/lists/*
# Install architecture-specific packages
RUN apt-get update && \
if [ "$TARGET_ARCH" = "amd64" ]; then \
apt-get install -y \
grub-efi-amd64-bin \
grub-efi-amd64-signed \
grub-pc-bin \
shim-signed \
syslinux-utils \
syslinux \
syslinux-common \
isolinux; \
elif [ "$TARGET_ARCH" = "arm64" ]; then \
apt-get install -y \
grub-efi-arm64-bin \
grub-efi-arm64-signed; \
elif [ "$TARGET_ARCH" = "rpi" ]; then \
apt-get install -y \
grub-efi-arm64-bin; \
fi && rm -rf /var/lib/apt/lists/*
# Install Deno
RUN curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh
@@ -45,16 +64,29 @@ COPY isobuild/config/hooks/ /build/hooks/
# Copy daemon source (for bundling)
COPY ecoos_daemon/ /daemon/
# Bundle the daemon
RUN cd /daemon && deno compile --allow-all --output /build/daemon-bundle/eco-daemon mod.ts
# Bundle the daemon - cross-compile for target architecture
RUN cd /daemon && \
if [ "$TARGET_ARCH" = "amd64" ]; then \
deno compile --allow-all --target x86_64-unknown-linux-gnu --output /build/daemon-bundle/eco-daemon mod.ts; \
else \
deno compile --allow-all --target aarch64-unknown-linux-gnu --output /build/daemon-bundle/eco-daemon mod.ts; \
fi
# Download Chromium during Docker build (network works here, not in chroot hooks)
RUN echo "Downloading Chromium from official snapshots..." && \
# Note: ARM64 Chromium snapshots may be less reliable, fallback to known version
RUN echo "Downloading Chromium for $TARGET_ARCH..." && \
cd /tmp && \
LATEST=$(curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2FLAST_CHANGE?alt=media" 2>/dev/null || echo "1368529") && \
echo "Using Chromium build: $LATEST" && \
curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2F${LATEST}%2Fchrome-linux.zip?alt=media" -o chromium.zip || \
curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/Linux_x64%2F1368529%2Fchrome-linux.zip?alt=media" -o chromium.zip && \
if [ "$TARGET_ARCH" = "amd64" ]; then \
PLATFORM="Linux_x64"; \
FALLBACK_VERSION="1368529"; \
else \
PLATFORM="Linux_ARM64"; \
FALLBACK_VERSION="1368529"; \
fi && \
LATEST=$(curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/${PLATFORM}%2FLAST_CHANGE?alt=media" 2>/dev/null || echo "$FALLBACK_VERSION") && \
echo "Using Chromium build: $LATEST for platform $PLATFORM" && \
curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/${PLATFORM}%2F${LATEST}%2Fchrome-linux.zip?alt=media" -o chromium.zip || \
curl -fsSL "https://www.googleapis.com/download/storage/v1/b/chromium-browser-snapshots/o/${PLATFORM}%2F${FALLBACK_VERSION}%2Fchrome-linux.zip?alt=media" -o chromium.zip && \
mkdir -p /build/chromium && \
unzip -q chromium.zip -d /tmp && \
mv /tmp/chrome-linux/* /build/chromium/ && \
@@ -71,21 +103,45 @@ RUN echo '#!/bin/sh' > /usr/local/bin/isohybrid && \
echo 'exit 0' >> /usr/local/bin/isohybrid && \
chmod +x /usr/local/bin/isohybrid
# Build script
# Build script - parameterized for architecture
COPY <<'EOF' /build/docker-build.sh
#!/bin/bash
set -e
export PATH="/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin:$PATH"
# Get architecture from environment (passed from docker run -e)
TARGET_ARCH="${TARGET_ARCH:-amd64}"
echo "=== EcoOS ISO Builder (Docker) ==="
echo "Target architecture: $TARGET_ARCH"
cd /build
# Initialize live-build - UEFI only (no syslinux/BIOS)
# Using German mirror for faster/more stable downloads
# Determine live-build architecture and image format
case "$TARGET_ARCH" in
amd64)
LB_ARCH="amd64"
IMAGE_FORMAT="iso-hybrid"
BOOTLOADER_OPT="--bootloader grub-efi"
;;
arm64)
LB_ARCH="arm64"
IMAGE_FORMAT="iso-hybrid"
BOOTLOADER_OPT="--bootloader grub-efi"
;;
rpi)
LB_ARCH="arm64"
IMAGE_FORMAT="hdd"
BOOTLOADER_OPT="" # RPi uses native bootloader
;;
esac
echo "Live-build arch: $LB_ARCH, format: $IMAGE_FORMAT"
# Initialize live-build
lb config \
--architectures amd64 \
--architectures $LB_ARCH \
--distribution noble \
--archive-areas "main restricted universe multiverse" \
--mirror-bootstrap "http://ftp.halifax.rwth-aachen.de/ubuntu/" \
@@ -93,16 +149,33 @@ lb config \
--mirror-chroot-security "http://ftp.halifax.rwth-aachen.de/ubuntu/" \
--mirror-binary "http://ftp.halifax.rwth-aachen.de/ubuntu/" \
--mirror-binary-security "http://ftp.halifax.rwth-aachen.de/ubuntu/" \
--binary-images iso-hybrid \
--binary-images $IMAGE_FORMAT \
--debian-installer false \
--memtest none \
--bootloader grub-efi \
$BOOTLOADER_OPT \
--iso-application "EcoOS" \
--iso-publisher "EcoBridge" \
--iso-volume "EcoOS"
# Copy package lists
cp /build/config/live-build/package-lists/*.list.chroot config/package-lists/
# Copy common package lists (excluding architecture-specific ones)
for f in /build/config/live-build/package-lists/*.list.chroot; do
filename=$(basename "$f")
# Skip architecture-specific files (base-amd64, base-arm64, base-rpi)
case "$filename" in
base-amd64.list.chroot|base-arm64.list.chroot|base-rpi.list.chroot)
echo "Skipping arch-specific list: $filename"
;;
*)
cp "$f" config/package-lists/
;;
esac
done
# Append architecture-specific packages to base.list.chroot
if [ -f "/build/config/live-build/package-lists/base-${TARGET_ARCH}.list.chroot" ]; then
echo "Adding architecture-specific packages for $TARGET_ARCH..."
cat "/build/config/live-build/package-lists/base-${TARGET_ARCH}.list.chroot" >> config/package-lists/base.list.chroot
fi
# Prepare includes.chroot
mkdir -p config/includes.chroot/opt/eco/bin
@@ -154,26 +227,28 @@ mkdir -p config/includes.binary/autoinstall
cp /build/config/autoinstall/user-data config/includes.binary/autoinstall/
touch config/includes.binary/autoinstall/meta-data
# Prepare EFI boot files in includes.binary
echo "Preparing EFI boot structure..."
mkdir -p config/includes.binary/EFI/BOOT
mkdir -p config/includes.binary/boot/grub
# Architecture-specific EFI/boot setup
if [ "$TARGET_ARCH" = "amd64" ]; then
# AMD64 EFI boot setup
echo "Preparing AMD64 EFI boot structure..."
mkdir -p config/includes.binary/EFI/BOOT
mkdir -p config/includes.binary/boot/grub
# Copy signed EFI files from host (installed in Docker image)
cp /usr/lib/shim/shimx64.efi.signed.latest config/includes.binary/EFI/BOOT/BOOTX64.EFI || \
cp /usr/lib/shim/shimx64.efi.signed config/includes.binary/EFI/BOOT/BOOTX64.EFI || \
cp /usr/lib/shim/shimx64.efi config/includes.binary/EFI/BOOT/BOOTX64.EFI || true
# Copy signed EFI files from host (installed in Docker image)
cp /usr/lib/shim/shimx64.efi.signed.latest config/includes.binary/EFI/BOOT/BOOTX64.EFI || \
cp /usr/lib/shim/shimx64.efi.signed config/includes.binary/EFI/BOOT/BOOTX64.EFI || \
cp /usr/lib/shim/shimx64.efi config/includes.binary/EFI/BOOT/BOOTX64.EFI || true
cp /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed config/includes.binary/EFI/BOOT/grubx64.efi || \
cp /usr/lib/grub/x86_64-efi/grubx64.efi config/includes.binary/EFI/BOOT/grubx64.efi || true
cp /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed config/includes.binary/EFI/BOOT/grubx64.efi || \
cp /usr/lib/grub/x86_64-efi/grubx64.efi config/includes.binary/EFI/BOOT/grubx64.efi || true
# Also provide mmx64.efi for some UEFI implementations
if [ -f config/includes.binary/EFI/BOOT/grubx64.efi ]; then
cp config/includes.binary/EFI/BOOT/grubx64.efi config/includes.binary/EFI/BOOT/mmx64.efi
fi
# Also provide mmx64.efi for some UEFI implementations
if [ -f config/includes.binary/EFI/BOOT/grubx64.efi ]; then
cp config/includes.binary/EFI/BOOT/grubx64.efi config/includes.binary/EFI/BOOT/mmx64.efi
fi
# Create grub.cfg for live boot with installer option
cat > config/includes.binary/boot/grub/grub.cfg << 'GRUBCFG'
# Create grub.cfg for live boot with installer option
cat > config/includes.binary/boot/grub/grub.cfg << 'GRUBCFG'
set default=0
set timeout=10
@@ -198,82 +273,174 @@ menuentry "EcoOS Live (Safe Mode)" {
}
GRUBCFG
# Also put grub.cfg in EFI/BOOT for fallback
cp config/includes.binary/boot/grub/grub.cfg config/includes.binary/EFI/BOOT/grub.cfg
# Also put grub.cfg in EFI/BOOT for fallback
cp config/includes.binary/boot/grub/grub.cfg config/includes.binary/EFI/BOOT/grub.cfg
# Build ISO - use individual lb stages to control the process
lb bootstrap
lb chroot
elif [ "$TARGET_ARCH" = "arm64" ]; then
# ARM64 EFI boot setup
echo "Preparing ARM64 EFI boot structure..."
mkdir -p config/includes.binary/EFI/BOOT
mkdir -p config/includes.binary/boot/grub
# Try lb binary, but continue even if isohybrid fails
lb binary || {
echo "lb binary had errors, checking if ISO was created anyway..."
if ls /build/*.iso 2>/dev/null; then
echo "ISO exists despite errors, continuing..."
else
echo "No ISO found, build truly failed"
exit 1
fi
}
# Copy ARM64 GRUB EFI
cp /usr/lib/grub/arm64-efi-signed/grubaa64.efi.signed config/includes.binary/EFI/BOOT/BOOTAA64.EFI || \
cp /usr/lib/grub/arm64-efi/grubaa64.efi config/includes.binary/EFI/BOOT/BOOTAA64.EFI || true
# Check if EFI was created properly
echo "Checking binary directory for EFI..."
ls -la binary/EFI/BOOT/ 2>/dev/null || echo "EFI/BOOT not found in binary dir"
# Find the ISO file
echo "Searching for ISO file..."
find /build -name "*.iso" -type f 2>/dev/null
ls -la /build/*.iso 2>/dev/null || true
ISO_FILE=$(find /build -name "*.iso" -type f 2>/dev/null | head -1)
if [ -z "$ISO_FILE" ]; then
echo "ERROR: No ISO file found in build directory"
echo "Listing /build contents:"
ls -la /build/
exit 1
fi
echo "Found ISO: $ISO_FILE"
# Always create proper EFI boot image and rebuild ISO
echo "Creating UEFI-bootable ISO..."
# Extract ISO contents
mkdir -p /tmp/iso_extract
xorriso -osirrox on -indev "$ISO_FILE" -extract / /tmp/iso_extract
# Find the actual kernel and initrd names
VMLINUZ=$(ls /tmp/iso_extract/casper/vmlinuz* 2>/dev/null | head -1 | xargs basename)
INITRD=$(ls /tmp/iso_extract/casper/initrd* 2>/dev/null | head -1 | xargs basename)
echo "Found kernel: $VMLINUZ, initrd: $INITRD"
# Ensure EFI structure exists with proper files
mkdir -p /tmp/iso_extract/EFI/BOOT
mkdir -p /tmp/iso_extract/boot/grub
# Copy EFI files from host
cp /usr/lib/shim/shimx64.efi.signed.latest /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || \
cp /usr/lib/shim/shimx64.efi.signed /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || \
cp /usr/lib/shim/shimx64.efi /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || true
cp /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed /tmp/iso_extract/EFI/BOOT/grubx64.efi 2>/dev/null || \
cp /usr/lib/grub/x86_64-efi/grubx64.efi /tmp/iso_extract/EFI/BOOT/grubx64.efi 2>/dev/null || true
# Copy mmx64.efi for secure boot compatibility
if [ -f /tmp/iso_extract/EFI/BOOT/grubx64.efi ]; then
cp /tmp/iso_extract/EFI/BOOT/grubx64.efi /tmp/iso_extract/EFI/BOOT/mmx64.efi
fi
# Create grub.cfg with correct filenames and installer option
cat > /tmp/iso_extract/boot/grub/grub.cfg << GRUBCFG2
# Create grub.cfg for ARM64
cat > config/includes.binary/boot/grub/grub.cfg << 'GRUBCFG'
set default=0
set timeout=10
insmod part_gpt
insmod fat
insmod efi_gop
insmod efi_uga
menuentry "Install EcoOS (auto-selects in 10s)" {
linux /casper/vmlinuz boot=casper noprompt quiet splash ecoos_install=1 ---
initrd /casper/initrd
}
menuentry "EcoOS Live (Try without installing)" {
linux /casper/vmlinuz boot=casper noprompt quiet splash ---
initrd /casper/initrd
}
menuentry "EcoOS Live (Safe Mode)" {
linux /casper/vmlinuz boot=casper noprompt nomodeset ---
initrd /casper/initrd
}
GRUBCFG
cp config/includes.binary/boot/grub/grub.cfg config/includes.binary/EFI/BOOT/grub.cfg
elif [ "$TARGET_ARCH" = "rpi" ]; then
# Raspberry Pi boot setup (native bootloader, no GRUB)
echo "Preparing Raspberry Pi boot structure..."
mkdir -p config/includes.binary/boot
# Create config.txt for Raspberry Pi
cat > config/includes.binary/boot/config.txt << 'PICFG'
# EcoOS Raspberry Pi Configuration
# Supports Pi 3, 4, and 5
# Enable 64-bit mode
arm_64bit=1
# Kernel and initrd
kernel=vmlinuz
initramfs initrd.img followkernel
# Enable serial console for debugging
enable_uart=1
# GPU/display settings
dtoverlay=vc4-kms-v3d
gpu_mem=256
# USB and power settings (Pi 4/5)
max_usb_current=1
# Audio
dtparam=audio=on
# Camera/display interfaces
camera_auto_detect=1
display_auto_detect=1
# Pi 5 specific (ignored on older models)
[pi5]
dtoverlay=dwc2,dr_mode=host
PICFG
# Create cmdline.txt
cat > config/includes.binary/boot/cmdline.txt << 'CMDLINE'
console=serial0,115200 console=tty1 root=LABEL=EcoOS rootfstype=ext4 fsck.repair=yes rootwait quiet splash
CMDLINE
fi
# Build - use individual lb stages to control the process
echo "Running lb bootstrap..."
lb bootstrap
echo "Running lb chroot..."
lb chroot
# Try lb binary, but continue even if isohybrid fails
echo "Running lb binary..."
lb binary || {
echo "lb binary had errors, checking if output was created anyway..."
if ls /build/*.iso 2>/dev/null || ls /build/*.img 2>/dev/null; then
echo "Output exists despite errors, continuing..."
else
echo "No output found, build truly failed"
exit 1
fi
}
# Post-processing based on architecture
if [ "$TARGET_ARCH" = "amd64" ] || [ "$TARGET_ARCH" = "arm64" ]; then
# Find the ISO file
echo "Searching for ISO file..."
find /build -name "*.iso" -type f 2>/dev/null
ls -la /build/*.iso 2>/dev/null || true
ISO_FILE=$(find /build -name "*.iso" -type f 2>/dev/null | head -1)
if [ -z "$ISO_FILE" ]; then
echo "ERROR: No ISO file found in build directory"
ls -la /build/
exit 1
fi
echo "Found ISO: $ISO_FILE"
# Rebuild ISO with proper EFI boot support
echo "Creating UEFI-bootable ISO..."
# Extract ISO contents
mkdir -p /tmp/iso_extract
xorriso -osirrox on -indev "$ISO_FILE" -extract / /tmp/iso_extract
# Find the actual kernel and initrd names
VMLINUZ=$(ls /tmp/iso_extract/casper/vmlinuz* 2>/dev/null | head -1 | xargs basename)
INITRD=$(ls /tmp/iso_extract/casper/initrd* 2>/dev/null | head -1 | xargs basename)
echo "Found kernel: $VMLINUZ, initrd: $INITRD"
# Ensure EFI structure exists with proper files
mkdir -p /tmp/iso_extract/EFI/BOOT
mkdir -p /tmp/iso_extract/boot/grub
if [ "$TARGET_ARCH" = "amd64" ]; then
# Copy AMD64 EFI files
cp /usr/lib/shim/shimx64.efi.signed.latest /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || \
cp /usr/lib/shim/shimx64.efi.signed /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || \
cp /usr/lib/shim/shimx64.efi /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI 2>/dev/null || true
cp /usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed /tmp/iso_extract/EFI/BOOT/grubx64.efi 2>/dev/null || \
cp /usr/lib/grub/x86_64-efi/grubx64.efi /tmp/iso_extract/EFI/BOOT/grubx64.efi 2>/dev/null || true
if [ -f /tmp/iso_extract/EFI/BOOT/grubx64.efi ]; then
cp /tmp/iso_extract/EFI/BOOT/grubx64.efi /tmp/iso_extract/EFI/BOOT/mmx64.efi
fi
EFI_BOOT_FILE="BOOTX64.EFI"
else
# Copy ARM64 EFI files
cp /usr/lib/grub/arm64-efi-signed/grubaa64.efi.signed /tmp/iso_extract/EFI/BOOT/BOOTAA64.EFI 2>/dev/null || \
cp /usr/lib/grub/arm64-efi/grubaa64.efi /tmp/iso_extract/EFI/BOOT/BOOTAA64.EFI 2>/dev/null || true
EFI_BOOT_FILE="BOOTAA64.EFI"
fi
# Update grub.cfg with correct filenames
cat > /tmp/iso_extract/boot/grub/grub.cfg << GRUBCFG2
set default=0
set timeout=10
insmod part_gpt
insmod fat
insmod efi_gop
$([ "$TARGET_ARCH" = "amd64" ] && echo "insmod efi_uga")
menuentry "Install EcoOS (auto-selects in 10s)" {
linux /casper/${VMLINUZ} boot=casper noprompt quiet splash ecoos_install=1 ---
@@ -291,54 +458,86 @@ menuentry "EcoOS Live (Safe Mode)" {
}
GRUBCFG2
cp /tmp/iso_extract/boot/grub/grub.cfg /tmp/iso_extract/EFI/BOOT/grub.cfg
cp /tmp/iso_extract/boot/grub/grub.cfg /tmp/iso_extract/EFI/BOOT/grub.cfg
# Create EFI boot image (FAT filesystem for UEFI El Torito boot)
echo "Creating EFI boot image..."
dd if=/dev/zero of=/tmp/efi.img bs=1M count=10
mkfs.fat -F 12 /tmp/efi.img
mmd -i /tmp/efi.img ::/EFI
mmd -i /tmp/efi.img ::/EFI/BOOT
mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/BOOTX64.EFI ::/EFI/BOOT/
mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/grubx64.efi ::/EFI/BOOT/ 2>/dev/null || true
mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/mmx64.efi ::/EFI/BOOT/ 2>/dev/null || true
mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/grub.cfg ::/EFI/BOOT/
# Create EFI boot image (FAT filesystem for UEFI El Torito boot)
echo "Creating EFI boot image..."
dd if=/dev/zero of=/tmp/efi.img bs=1M count=10
mkfs.fat -F 12 /tmp/efi.img
mmd -i /tmp/efi.img ::/EFI
mmd -i /tmp/efi.img ::/EFI/BOOT
mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/$EFI_BOOT_FILE ::/EFI/BOOT/
if [ "$TARGET_ARCH" = "amd64" ]; then
mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/grubx64.efi ::/EFI/BOOT/ 2>/dev/null || true
mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/mmx64.efi ::/EFI/BOOT/ 2>/dev/null || true
fi
mcopy -i /tmp/efi.img /tmp/iso_extract/EFI/BOOT/grub.cfg ::/EFI/BOOT/
# Rebuild ISO with EFI boot support (UEFI-only, no BIOS boot)
echo "Rebuilding ISO with UEFI boot support..."
xorriso -as mkisofs \
-r -V "EcoOS" \
-o /tmp/ecoos-efi.iso \
-J -joliet-long \
-eltorito-alt-boot \
-e --interval:appended_partition_2:all:: \
-no-emul-boot -isohybrid-gpt-basdat \
-append_partition 2 0xef /tmp/efi.img \
/tmp/iso_extract
# Rebuild ISO with EFI boot support
echo "Rebuilding ISO with UEFI boot support..."
xorriso -as mkisofs \
-r -V "EcoOS" \
-o /tmp/ecoos-efi.iso \
-J -joliet-long \
-eltorito-alt-boot \
-e --interval:appended_partition_2:all:: \
-no-emul-boot -isohybrid-gpt-basdat \
-append_partition 2 0xef /tmp/efi.img \
/tmp/iso_extract
if [ -f /tmp/ecoos-efi.iso ]; then
ISO_FILE=/tmp/ecoos-efi.iso
echo "Created UEFI-bootable ISO: $ISO_FILE"
else
echo "ERROR: Failed to create EFI ISO"
exit 1
if [ -f /tmp/ecoos-efi.iso ]; then
ISO_FILE=/tmp/ecoos-efi.iso
echo "Created UEFI-bootable ISO: $ISO_FILE"
else
echo "ERROR: Failed to create EFI ISO"
exit 1
fi
rm -rf /tmp/iso_extract
# Determine output filename
if [ "$TARGET_ARCH" = "amd64" ]; then
OUTPUT_NAME="ecoos.iso"
else
OUTPUT_NAME="ecoos-arm64.iso"
fi
# Copy to output
mkdir -p /output
cp "$ISO_FILE" /output/$OUTPUT_NAME
echo ""
echo "=== Final ISO EFI check ==="
xorriso -indev /output/$OUTPUT_NAME -find / -maxdepth 2 -type d 2>/dev/null || true
echo ""
echo "=== Build Complete ==="
echo "ISO: /output/$OUTPUT_NAME"
ls -lh /output/$OUTPUT_NAME
elif [ "$TARGET_ARCH" = "rpi" ]; then
# Raspberry Pi image creation
echo "Creating Raspberry Pi bootable image..."
# Find the live-build output
HDD_FILE=$(find /build -name "*.img" -type f 2>/dev/null | head -1)
SQUASHFS_FILE=$(find /build -name "filesystem.squashfs" -type f 2>/dev/null | head -1)
if [ -z "$SQUASHFS_FILE" ]; then
echo "Looking for squashfs in chroot..."
SQUASHFS_FILE=$(find /build/chroot -name "filesystem.squashfs" -type f 2>/dev/null | head -1)
fi
echo "Found squashfs: $SQUASHFS_FILE"
# Create RPi image using the helper script
/build/scripts/create-rpi-image.sh "$SQUASHFS_FILE" /output/ecoos-rpi.img
echo ""
echo "=== Build Complete ==="
echo "Image: /output/ecoos-rpi.img"
ls -lh /output/ecoos-rpi.img
fi
rm -rf /tmp/iso_extract
# Copy to output
mkdir -p /output
cp "$ISO_FILE" /output/ecoos.iso
# Final verification
echo ""
echo "=== Final ISO EFI check ==="
xorriso -indev /output/ecoos.iso -find / -maxdepth 2 -type d 2>/dev/null || true
echo ""
echo "=== Build Complete ==="
echo "ISO: /output/ecoos.iso"
ls -lh /output/ecoos.iso
EOF
RUN chmod +x /build/docker-build.sh

View File

@@ -1,7 +1,8 @@
#!/bin/bash
#
# EcoOS Installer
# Installs EcoOS from live USB to disk
# Installs EcoOS from live USB/SD to disk
# Supports: x86_64 (UEFI), ARM64 (UEFI), Raspberry Pi (native boot)
#
set -e
@@ -12,6 +13,45 @@ HOSTNAME="ecoos"
USERNAME="ecouser"
SQUASHFS_PATH="/run/live/medium/live/filesystem.squashfs"
# Detect architecture
detect_architecture() {
local arch=$(uname -m)
local is_rpi="no"
# Check if running on Raspberry Pi
if [ -f /sys/firmware/devicetree/base/model ]; then
local model=$(cat /sys/firmware/devicetree/base/model 2>/dev/null || echo "")
if [[ "$model" == *"Raspberry Pi"* ]]; then
is_rpi="yes"
fi
fi
case "$arch" in
x86_64)
ARCH_TYPE="amd64"
BOOT_TYPE="uefi"
;;
aarch64)
if [ "$is_rpi" = "yes" ]; then
ARCH_TYPE="rpi"
BOOT_TYPE="rpi"
else
ARCH_TYPE="arm64"
BOOT_TYPE="uefi"
fi
;;
*)
ARCH_TYPE="unknown"
BOOT_TYPE="unknown"
;;
esac
export ARCH_TYPE BOOT_TYPE
}
# Call architecture detection early
detect_architecture
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
@@ -191,43 +231,66 @@ select_disk() {
partition_disk() {
local disk=$1
log "Partitioning $disk..."
log "Partitioning $disk for $ARCH_TYPE ($BOOT_TYPE boot)..."
# Wipe existing partition table
wipefs -a "$disk" >/dev/null 2>&1 || true
# Create GPT partition table
parted -s "$disk" mklabel gpt
if [ "$BOOT_TYPE" = "rpi" ]; then
# Raspberry Pi uses MBR partition table
log "Creating MBR partition table for Raspberry Pi..."
parted -s "$disk" mklabel msdos
# Create EFI partition (512MB)
parted -s "$disk" mkpart ESP fat32 1MiB 513MiB
parted -s "$disk" set 1 esp on
# Create boot partition (FAT32, 256MB)
parted -s "$disk" mkpart primary fat32 1MiB 257MiB
parted -s "$disk" set 1 boot on
# Create root partition (rest of disk)
parted -s "$disk" mkpart root ext4 513MiB 100%
# Create root partition (rest of disk)
parted -s "$disk" mkpart primary ext4 257MiB 100%
else
# x86_64 and generic ARM64 use GPT with EFI
log "Creating GPT partition table with EFI..."
parted -s "$disk" mklabel gpt
# Create EFI partition (512MB)
parted -s "$disk" mkpart ESP fat32 1MiB 513MiB
parted -s "$disk" set 1 esp on
# Create root partition (rest of disk)
parted -s "$disk" mkpart root ext4 513MiB 100%
fi
# Wait for partitions to appear
sleep 2
partprobe "$disk"
sleep 1
# Determine partition names (nvme vs sd)
if [[ "$disk" == *"nvme"* ]]; then
EFI_PART="${disk}p1"
# Determine partition names (nvme vs sd vs mmcblk)
if [[ "$disk" == *"nvme"* ]] || [[ "$disk" == *"mmcblk"* ]]; then
BOOT_PART="${disk}p1"
ROOT_PART="${disk}p2"
else
EFI_PART="${disk}1"
BOOT_PART="${disk}1"
ROOT_PART="${disk}2"
fi
log "Created partitions: EFI=$EFI_PART, Root=$ROOT_PART"
# For UEFI systems, BOOT_PART is the EFI partition
if [ "$BOOT_TYPE" = "uefi" ]; then
EFI_PART="$BOOT_PART"
fi
log "Created partitions: Boot=$BOOT_PART, Root=$ROOT_PART"
}
# Format partitions
format_partitions() {
log "Formatting partitions..."
mkfs.fat -F 32 -n "EFI" "$EFI_PART"
if [ "$BOOT_TYPE" = "rpi" ]; then
mkfs.fat -F 32 -n "boot" "$BOOT_PART"
else
mkfs.fat -F 32 -n "EFI" "$EFI_PART"
fi
mkfs.ext4 -F -L "EcoOS" "$ROOT_PART"
log "Partitions formatted"
@@ -240,8 +303,15 @@ mount_partitions() {
mkdir -p /mnt/target
mount "$ROOT_PART" /mnt/target
mkdir -p /mnt/target/boot/efi
mount "$EFI_PART" /mnt/target/boot/efi
if [ "$BOOT_TYPE" = "rpi" ]; then
# Raspberry Pi mounts boot at /boot
mkdir -p /mnt/target/boot
mount "$BOOT_PART" /mnt/target/boot
else
# UEFI systems mount EFI at /boot/efi
mkdir -p /mnt/target/boot/efi
mount "$EFI_PART" /mnt/target/boot/efi
fi
log "Partitions mounted at /mnt/target"
}
@@ -292,14 +362,22 @@ configure_system() {
# Get UUIDs
local root_uuid=$(blkid -s UUID -o value "$ROOT_PART")
local efi_uuid=$(blkid -s UUID -o value "$EFI_PART")
local boot_uuid=$(blkid -s UUID -o value "$BOOT_PART")
# Create fstab
cat > /mnt/target/etc/fstab << EOF
# Create fstab based on boot type
if [ "$BOOT_TYPE" = "rpi" ]; then
cat > /mnt/target/etc/fstab << EOF
# EcoOS fstab - Raspberry Pi
UUID=$root_uuid / ext4 defaults,noatime 0 1
UUID=$boot_uuid /boot vfat defaults 0 2
EOF
else
cat > /mnt/target/etc/fstab << EOF
# EcoOS fstab
UUID=$root_uuid / ext4 defaults,noatime 0 1
UUID=$efi_uuid /boot/efi vfat umask=0077 0 1
UUID=$boot_uuid /boot/efi vfat umask=0077 0 1
EOF
fi
# Set hostname
echo "$HOSTNAME" > /mnt/target/etc/hostname
@@ -406,9 +484,89 @@ NETEOF
log "System configured"
}
# Configure Raspberry Pi boot files
configure_rpi_boot() {
log "Configuring Raspberry Pi boot files..."
local root_uuid=$(blkid -s UUID -o value "$ROOT_PART")
# Copy kernel and initrd to boot partition
local kernel=$(ls /mnt/target/boot/vmlinuz-* 2>/dev/null | sort -V | tail -1)
local initrd=$(ls /mnt/target/boot/initrd.img-* 2>/dev/null | sort -V | tail -1)
if [ -n "$kernel" ]; then
cp "$kernel" /mnt/target/boot/vmlinuz
log "Copied kernel: $(basename $kernel)"
fi
if [ -n "$initrd" ]; then
cp "$initrd" /mnt/target/boot/initrd.img
log "Copied initrd: $(basename $initrd)"
fi
# Copy device tree blobs
local dtb_dir=$(ls -d /mnt/target/usr/lib/linux-image-*-raspi 2>/dev/null | tail -1)
if [ -d "$dtb_dir/broadcom" ]; then
cp "$dtb_dir/broadcom"/*.dtb /mnt/target/boot/ 2>/dev/null || true
log "Copied device tree blobs"
fi
if [ -d "$dtb_dir/overlays" ]; then
mkdir -p /mnt/target/boot/overlays
cp -r "$dtb_dir/overlays"/* /mnt/target/boot/overlays/ 2>/dev/null || true
log "Copied device tree overlays"
fi
# Copy Pi firmware files
if [ -d /mnt/target/usr/lib/raspi-firmware ]; then
cp /mnt/target/usr/lib/raspi-firmware/*.bin /mnt/target/boot/ 2>/dev/null || true
cp /mnt/target/usr/lib/raspi-firmware/*.elf /mnt/target/boot/ 2>/dev/null || true
cp /mnt/target/usr/lib/raspi-firmware/*.dat /mnt/target/boot/ 2>/dev/null || true
log "Copied Raspberry Pi firmware"
fi
# Create config.txt
cat > /mnt/target/boot/config.txt << 'EOF'
# EcoOS Raspberry Pi Configuration
# Supports Pi 3, 4, and 5
# Enable 64-bit mode
arm_64bit=1
# Kernel and initrd
kernel=vmlinuz
initramfs initrd.img followkernel
# Enable serial console for debugging
enable_uart=1
# GPU/display settings
dtoverlay=vc4-kms-v3d
gpu_mem=256
# USB and power settings (Pi 4/5)
max_usb_current=1
# Audio
dtparam=audio=on
# Camera/display interfaces
camera_auto_detect=1
display_auto_detect=1
# Pi 5 specific (ignored on older models)
[pi5]
dtoverlay=dwc2,dr_mode=host
EOF
# Create cmdline.txt with root UUID
echo "console=serial0,115200 console=tty1 root=UUID=$root_uuid rootfstype=ext4 fsck.repair=yes rootwait quiet splash" > /mnt/target/boot/cmdline.txt
log "Raspberry Pi boot configured"
}
# Install bootloader
install_bootloader() {
log "Installing GRUB bootloader..."
log "Installing bootloader for $ARCH_TYPE ($BOOT_TYPE)..."
# Mount necessary filesystems for chroot
mount --bind /dev /mnt/target/dev
@@ -417,22 +575,7 @@ install_bootloader() {
mount --bind /sys /mnt/target/sys
mount --bind /run /mnt/target/run
# Fix GRUB default config - remove casper/live boot parameters and add serial console
if [ -f /mnt/target/etc/default/grub ]; then
# Remove any boot=casper or live-related parameters
sed -i 's/boot=casper//g' /mnt/target/etc/default/grub
# Update GRUB_CMDLINE_LINUX_DEFAULT with serial console for debugging
sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200n8"/' /mnt/target/etc/default/grub
# If line doesn't exist, add it
if ! grep -q "GRUB_CMDLINE_LINUX_DEFAULT" /mnt/target/etc/default/grub; then
echo 'GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200n8"' >> /mnt/target/etc/default/grub
fi
# Enable serial terminal in GRUB
echo 'GRUB_TERMINAL="console serial"' >> /mnt/target/etc/default/grub
echo 'GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"' >> /mnt/target/etc/default/grub
fi
# Disable casper-related services
# Disable casper-related services (common to all architectures)
log "Disabling live boot services..."
chroot /mnt/target systemctl disable casper.service 2>/dev/null || true
chroot /mnt/target systemctl disable casper-md5check.service 2>/dev/null || true
@@ -454,11 +597,38 @@ install_bootloader() {
# Ensure proper boot target
chroot /mnt/target systemctl set-default multi-user.target 2>/dev/null || true
# Install GRUB
chroot /mnt/target grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=EcoOS --recheck
if [ "$BOOT_TYPE" = "rpi" ]; then
# Raspberry Pi uses native bootloader (no GRUB)
configure_rpi_boot
else
# UEFI systems use GRUB
log "Installing GRUB bootloader..."
# Generate GRUB config
chroot /mnt/target update-grub
# Fix GRUB default config - remove casper/live boot parameters and add serial console
if [ -f /mnt/target/etc/default/grub ]; then
# Remove any boot=casper or live-related parameters
sed -i 's/boot=casper//g' /mnt/target/etc/default/grub
# Update GRUB_CMDLINE_LINUX_DEFAULT with serial console for debugging
sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200n8"/' /mnt/target/etc/default/grub
# If line doesn't exist, add it
if ! grep -q "GRUB_CMDLINE_LINUX_DEFAULT" /mnt/target/etc/default/grub; then
echo 'GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200n8"' >> /mnt/target/etc/default/grub
fi
# Enable serial terminal in GRUB
echo 'GRUB_TERMINAL="console serial"' >> /mnt/target/etc/default/grub
echo 'GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"' >> /mnt/target/etc/default/grub
fi
# Install GRUB based on architecture
if [ "$ARCH_TYPE" = "amd64" ]; then
chroot /mnt/target grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=EcoOS --recheck
elif [ "$ARCH_TYPE" = "arm64" ]; then
chroot /mnt/target grub-install --target=arm64-efi --efi-directory=/boot/efi --bootloader-id=EcoOS --recheck
fi
# Generate GRUB config
chroot /mnt/target update-grub
fi
# Cleanup mounts (use lazy unmount for stubborn mounts, reverse order)
sync
@@ -478,8 +648,12 @@ cleanup_and_reboot() {
# Sync disks
sync
# Unmount
umount /mnt/target/boot/efi
# Unmount based on boot type
if [ "$BOOT_TYPE" = "rpi" ]; then
umount /mnt/target/boot
else
umount /mnt/target/boot/efi
fi
umount /mnt/target
echo ""

View File

@@ -0,0 +1,10 @@
# AMD64-specific packages
# These are appended to base.list.chroot for amd64 builds
# EFI bootloader (required for UEFI boot on x86_64)
grub-efi-amd64
grub-efi-amd64-signed
shim-signed
# x86_64 kernel (same as generic, included for clarity)
# linux-image-generic is already in base.list.chroot

View File

@@ -0,0 +1,9 @@
# ARM64-specific packages
# These are appended to base.list.chroot for arm64 builds
# EFI bootloader (required for UEFI boot on ARM64)
grub-efi-arm64
grub-efi-arm64-signed
# ARM64 kernel (generic works for most ARM64 UEFI systems)
# linux-image-generic is already in base.list.chroot

View File

@@ -0,0 +1,18 @@
# Raspberry Pi specific packages
# These are appended to base.list.chroot for rpi builds
# Raspberry Pi kernel (optimized for Pi hardware)
linux-image-raspi
linux-modules-extra-raspi
# Raspberry Pi firmware and utilities
linux-firmware-raspi
raspi-firmware
libraspberrypi-bin
libraspberrypi0
# Pi-specific hardware support
pi-bluetooth
rpi-eeprom
# Note: No GRUB packages - Pi uses native bootloader (config.txt + start.elf)

View File

@@ -1,4 +1,7 @@
# EcoOS Base Packages
# Common packages for all architectures
# Architecture-specific packages are in base-{amd64,arm64,rpi}.list.chroot
# System essentials
linux-image-generic
linux-headers-generic
@@ -8,10 +11,8 @@ network-manager
openssh-server
sudo
# EFI bootloader (required for UEFI boot)
grub-efi-amd64
grub-efi-amd64-signed
shim-signed
# Note: EFI bootloader packages are architecture-specific
# See base-amd64.list.chroot, base-arm64.list.chroot, base-rpi.list.chroot
# Sway + Wayland
sway

View File

@@ -0,0 +1,234 @@
#!/bin/bash
#
# Create Raspberry Pi bootable image from live-build output
# This script creates a proper Pi-bootable image with:
# - Partition 1: FAT32 boot partition (256MB) with Pi firmware
# - Partition 2: ext4 root filesystem
#
# Usage: ./create-rpi-image.sh <squashfs_or_chroot_path> <output_image>
#
set -e
INPUT_PATH="$1"
OUTPUT_IMG="$2"
IMG_SIZE="${3:-8G}"
if [ -z "$INPUT_PATH" ] || [ -z "$OUTPUT_IMG" ]; then
echo "Usage: $0 <squashfs_or_chroot_path> <output_image> [size]"
echo ""
echo "Arguments:"
echo " squashfs_or_chroot_path Path to filesystem.squashfs or chroot directory"
echo " output_image Output .img file path"
echo " size Image size (default: 8G)"
exit 1
fi
echo "=== Creating Raspberry Pi Image ==="
echo "Input: $INPUT_PATH"
echo "Output: $OUTPUT_IMG"
echo "Size: $IMG_SIZE"
# Create empty image
echo "Creating empty image..."
truncate -s $IMG_SIZE "$OUTPUT_IMG"
# Create partition table (MBR for Pi compatibility)
echo "Creating partition table..."
parted -s "$OUTPUT_IMG" mklabel msdos
parted -s "$OUTPUT_IMG" mkpart primary fat32 1MiB 257MiB
parted -s "$OUTPUT_IMG" mkpart primary ext4 257MiB 100%
parted -s "$OUTPUT_IMG" set 1 boot on
# Setup loop device
echo "Setting up loop device..."
LOOP_DEV=$(losetup --find --show --partscan "$OUTPUT_IMG")
echo "Loop device: $LOOP_DEV"
# Wait for partitions to appear
sleep 2
BOOT_PART="${LOOP_DEV}p1"
ROOT_PART="${LOOP_DEV}p2"
# Verify partitions exist
if [ ! -b "$BOOT_PART" ] || [ ! -b "$ROOT_PART" ]; then
echo "ERROR: Partitions not found. Trying partx..."
partx -a "$LOOP_DEV" 2>/dev/null || true
sleep 2
fi
echo "Boot partition: $BOOT_PART"
echo "Root partition: $ROOT_PART"
# Format partitions
echo "Formatting partitions..."
mkfs.vfat -F 32 -n "boot" "$BOOT_PART"
mkfs.ext4 -L "EcoOS" "$ROOT_PART"
# Create mount points
BOOT_MNT=$(mktemp -d)
ROOT_MNT=$(mktemp -d)
# Mount partitions
echo "Mounting partitions..."
mount "$BOOT_PART" "$BOOT_MNT"
mount "$ROOT_PART" "$ROOT_MNT"
# Extract or copy rootfs
echo "Copying root filesystem..."
if [ -f "$INPUT_PATH" ] && file "$INPUT_PATH" | grep -q "Squashfs"; then
# It's a squashfs file - extract it
echo "Extracting squashfs..."
unsquashfs -f -d "$ROOT_MNT" "$INPUT_PATH"
elif [ -d "$INPUT_PATH" ]; then
# It's a directory (chroot) - copy it
echo "Copying chroot directory..."
cp -a "$INPUT_PATH"/* "$ROOT_MNT"/
else
echo "ERROR: Input path is neither a squashfs file nor a directory"
umount "$BOOT_MNT" "$ROOT_MNT"
losetup -d "$LOOP_DEV"
rm -rf "$BOOT_MNT" "$ROOT_MNT"
exit 1
fi
# Copy kernel and initrd to boot partition
echo "Setting up boot partition..."
# Find kernel and initrd
KERNEL=$(ls "$ROOT_MNT"/boot/vmlinuz-* 2>/dev/null | sort -V | tail -1)
INITRD=$(ls "$ROOT_MNT"/boot/initrd.img-* 2>/dev/null | sort -V | tail -1)
if [ -n "$KERNEL" ]; then
cp "$KERNEL" "$BOOT_MNT/vmlinuz"
echo "Copied kernel: $(basename $KERNEL)"
fi
if [ -n "$INITRD" ]; then
cp "$INITRD" "$BOOT_MNT/initrd.img"
echo "Copied initrd: $(basename $INITRD)"
fi
# Copy device tree blobs if present
if [ -d "$ROOT_MNT/usr/lib/linux-image-"*"-raspi" ]; then
DTB_DIR=$(ls -d "$ROOT_MNT/usr/lib/linux-image-"*"-raspi" 2>/dev/null | tail -1)
if [ -d "$DTB_DIR/broadcom" ]; then
cp -r "$DTB_DIR/broadcom"/*.dtb "$BOOT_MNT/" 2>/dev/null || true
echo "Copied device tree blobs"
fi
if [ -d "$DTB_DIR/overlays" ]; then
mkdir -p "$BOOT_MNT/overlays"
cp -r "$DTB_DIR/overlays"/* "$BOOT_MNT/overlays/" 2>/dev/null || true
echo "Copied device tree overlays"
fi
fi
# Copy Pi firmware files
echo "Copying Raspberry Pi firmware..."
if [ -d "$ROOT_MNT/usr/lib/raspi-firmware" ]; then
cp "$ROOT_MNT/usr/lib/raspi-firmware"/*.bin "$BOOT_MNT/" 2>/dev/null || true
cp "$ROOT_MNT/usr/lib/raspi-firmware"/*.elf "$BOOT_MNT/" 2>/dev/null || true
cp "$ROOT_MNT/usr/lib/raspi-firmware"/*.dat "$BOOT_MNT/" 2>/dev/null || true
echo "Copied firmware files from raspi-firmware"
elif [ -d "$ROOT_MNT/boot/firmware" ]; then
cp "$ROOT_MNT/boot/firmware"/*.bin "$BOOT_MNT/" 2>/dev/null || true
cp "$ROOT_MNT/boot/firmware"/*.elf "$BOOT_MNT/" 2>/dev/null || true
cp "$ROOT_MNT/boot/firmware"/*.dat "$BOOT_MNT/" 2>/dev/null || true
echo "Copied firmware files from /boot/firmware"
fi
# Create config.txt if not present
if [ ! -f "$BOOT_MNT/config.txt" ]; then
echo "Creating config.txt..."
cat > "$BOOT_MNT/config.txt" << 'EOF'
# EcoOS Raspberry Pi Configuration
# Supports Pi 3, 4, and 5
# Enable 64-bit mode
arm_64bit=1
# Kernel and initrd
kernel=vmlinuz
initramfs initrd.img followkernel
# Enable serial console for debugging
enable_uart=1
# GPU/display settings
dtoverlay=vc4-kms-v3d
gpu_mem=256
# USB and power settings (Pi 4/5)
max_usb_current=1
# Audio
dtparam=audio=on
# Camera/display interfaces
camera_auto_detect=1
display_auto_detect=1
# Pi 5 specific (ignored on older models)
[pi5]
dtoverlay=dwc2,dr_mode=host
EOF
fi
# Create cmdline.txt if not present
if [ ! -f "$BOOT_MNT/cmdline.txt" ]; then
echo "Creating cmdline.txt..."
# Get the UUID of the root partition
ROOT_UUID=$(blkid -s UUID -o value "$ROOT_PART")
if [ -n "$ROOT_UUID" ]; then
echo "console=serial0,115200 console=tty1 root=UUID=$ROOT_UUID rootfstype=ext4 fsck.repair=yes rootwait quiet splash" > "$BOOT_MNT/cmdline.txt"
else
echo "console=serial0,115200 console=tty1 root=LABEL=EcoOS rootfstype=ext4 fsck.repair=yes rootwait quiet splash" > "$BOOT_MNT/cmdline.txt"
fi
fi
# Update fstab in the root filesystem
echo "Updating /etc/fstab..."
BOOT_UUID=$(blkid -s UUID -o value "$BOOT_PART")
ROOT_UUID=$(blkid -s UUID -o value "$ROOT_PART")
cat > "$ROOT_MNT/etc/fstab" << EOF
# EcoOS fstab - Raspberry Pi
# <file system> <mount point> <type> <options> <dump> <pass>
# Root filesystem
UUID=$ROOT_UUID / ext4 defaults,noatime 0 1
# Boot partition
UUID=$BOOT_UUID /boot vfat defaults 0 2
# Swap (if needed)
# /swapfile none swap sw 0 0
EOF
# Create symlink for boot files in rootfs
mkdir -p "$ROOT_MNT/boot"
echo "Boot partition will be mounted at /boot"
# Set hostname
echo "ecoos-rpi" > "$ROOT_MNT/etc/hostname"
# Cleanup
echo "Cleaning up..."
sync
umount "$BOOT_MNT"
umount "$ROOT_MNT"
losetup -d "$LOOP_DEV"
rm -rf "$BOOT_MNT" "$ROOT_MNT"
# Final size
FINAL_SIZE=$(ls -lh "$OUTPUT_IMG" | awk '{print $5}')
echo ""
echo "=== Raspberry Pi Image Created ==="
echo "Output: $OUTPUT_IMG"
echo "Size: $FINAL_SIZE"
echo ""
echo "To flash to SD card:"
echo " sudo dd if=$OUTPUT_IMG of=/dev/sdX bs=4M status=progress"
echo ""
echo "Or use Raspberry Pi Imager for a safer flash."

View File

@@ -3,6 +3,8 @@
# Build EcoOS ISO using Docker
# This avoids needing to install live-build on the host
#
# Usage: ./docker-build.sh [--arch=amd64|arm64|rpi]
#
set -e
@@ -10,25 +12,110 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ISOBUILD_DIR="$(dirname "$SCRIPT_DIR")"
ECO_OS_DIR="$(dirname "$ISOBUILD_DIR")"
# Default architecture
TARGET_ARCH="amd64"
# Parse arguments
for arg in "$@"; do
case $arg in
--arch=*)
TARGET_ARCH="${arg#*=}"
;;
-h|--help)
echo "Usage: $0 [--arch=amd64|arm64|rpi]"
echo ""
echo "Architectures:"
echo " amd64 - x86_64 with UEFI/GRUB boot (default)"
echo " arm64 - Generic ARM64 with UEFI/GRUB boot"
echo " rpi - Raspberry Pi 3/4/5 with native bootloader"
exit 0
;;
*)
echo "Unknown argument: $arg"
echo "Use --help for usage information"
exit 1
;;
esac
done
# Validate architecture
case "$TARGET_ARCH" in
amd64|arm64|rpi)
;;
*)
echo "ERROR: Invalid architecture '$TARGET_ARCH'"
echo "Valid options: amd64, arm64, rpi"
exit 1
;;
esac
# Determine output filename based on architecture
case "$TARGET_ARCH" in
amd64)
OUTPUT_FILE="ecoos.iso"
;;
arm64)
OUTPUT_FILE="ecoos-arm64.iso"
;;
rpi)
OUTPUT_FILE="ecoos-rpi.img"
;;
esac
echo "=== EcoOS ISO Builder (Docker) ==="
echo "Target architecture: $TARGET_ARCH"
echo "Output file: $OUTPUT_FILE"
echo ""
cd "$ECO_OS_DIR"
# Build the Docker image
echo "[1/2] Building Docker image..."
docker build -t ecoos-builder -f isobuild/Dockerfile .
# Build the Docker image with architecture argument
echo "[1/2] Building Docker image for $TARGET_ARCH..."
# For ARM builds on x86 hosts, we need to use buildx with platform emulation
if [ "$TARGET_ARCH" = "arm64" ] || [ "$TARGET_ARCH" = "rpi" ]; then
HOST_ARCH=$(uname -m)
if [ "$HOST_ARCH" = "x86_64" ]; then
echo "Cross-building ARM on x86_64 host - using Docker buildx with QEMU emulation"
echo "Note: This requires QEMU binfmt. If this fails, run:"
echo " docker run --privileged --rm tonistiigi/binfmt --install all"
echo ""
# Ensure buildx is available and create builder if needed
docker buildx inspect ecoos-builder >/dev/null 2>&1 || \
docker buildx create --name ecoos-builder --use
docker buildx build \
--platform linux/arm64 \
--build-arg TARGET_ARCH="$TARGET_ARCH" \
--load \
-t ecoos-builder-$TARGET_ARCH \
-f isobuild/Dockerfile .
else
# Running on ARM host, use regular build
docker build \
--build-arg TARGET_ARCH="$TARGET_ARCH" \
-t ecoos-builder-$TARGET_ARCH \
-f isobuild/Dockerfile .
fi
else
docker build \
--build-arg TARGET_ARCH="$TARGET_ARCH" \
-t ecoos-builder-$TARGET_ARCH \
-f isobuild/Dockerfile .
fi
# Run the build
echo ""
echo "[2/2] Building ISO (this may take 15-30 minutes)..."
echo "[2/2] Building image (this may take 15-30 minutes)..."
mkdir -p "$ISOBUILD_DIR/output"
docker run --rm \
--privileged \
-e TARGET_ARCH="$TARGET_ARCH" \
-v "$ISOBUILD_DIR/output:/output" \
ecoos-builder
ecoos-builder-$TARGET_ARCH
echo ""
echo "=== Build Complete ==="
echo "ISO: $ISOBUILD_DIR/output/ecoos.iso"
echo "Output: $ISOBUILD_DIR/output/$OUTPUT_FILE"