Some checks failed
CI / Go Tests (push) Has been cancelled
CI / Build Go Binaries (amd64, linux, linux-amd64) (push) Has been cancelled
CI / Build Go Binaries (arm64, linux, linux-arm64) (push) Has been cancelled
CI / Shellcheck (push) Has been cancelled
Release / Test (push) Has been cancelled
Release / Build Binaries (amd64, linux, linux-amd64) (push) Has been cancelled
Release / Build Binaries (arm64, linux, linux-arm64) (push) Has been cancelled
Release / Build ISO (amd64) (push) Has been cancelled
Release / Create Release (push) Has been cancelled
- Add kpartx for reliable loop partition mapping in Docker containers - Fix piCore64 download URL (changed from .img.gz to .zip format) - Fix piCore64 boot partition mount (initramfs on p1, not p2) - Fix tar --wildcards for RPi firmware extraction - Add MIT license (same as KubeSolo) - Add kpartx and unzip to Docker builder image Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
187 lines
6.2 KiB
Bash
Executable File
187 lines
6.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# extract-core.sh — Extract Tiny Core Linux rootfs from ISO
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
CACHE_DIR="${CACHE_DIR:-$PROJECT_ROOT/build/cache}"
|
|
ROOTFS_DIR="${ROOTFS_DIR:-$PROJECT_ROOT/build/rootfs-work}"
|
|
|
|
# shellcheck source=../config/versions.env
|
|
. "$SCRIPT_DIR/../config/versions.env"
|
|
|
|
EXTRACT_ARCH="${TARGET_ARCH:-amd64}"
|
|
|
|
# Clean previous rootfs
|
|
rm -rf "$ROOTFS_DIR"
|
|
mkdir -p "$ROOTFS_DIR"
|
|
|
|
# =========================================================================
|
|
# ARM64: piCore64 .img.gz extraction (SD card image, not ISO)
|
|
# =========================================================================
|
|
if [ "$EXTRACT_ARCH" = "arm64" ]; then
|
|
PICORE_IMG="$CACHE_DIR/$PICORE_IMAGE"
|
|
if [ ! -f "$PICORE_IMG" ]; then
|
|
echo "ERROR: piCore64 image not found: $PICORE_IMG"
|
|
echo "Run 'TARGET_ARCH=arm64 make fetch' first."
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> Extracting piCore64 image: $PICORE_IMG"
|
|
|
|
# Decompress to raw image (.img.gz or .zip)
|
|
PICORE_RAW="$CACHE_DIR/piCore-${PICORE_VERSION}.img"
|
|
if [ ! -f "$PICORE_RAW" ]; then
|
|
echo " Decompressing..."
|
|
case "$PICORE_IMG" in
|
|
*.zip)
|
|
unzip -o -j "$PICORE_IMG" '*.img' -d "$CACHE_DIR" 2>/dev/null || \
|
|
unzip -o "$PICORE_IMG" -d "$CACHE_DIR"
|
|
# Find the extracted .img file
|
|
EXTRACTED_IMG=$(find "$CACHE_DIR" -maxdepth 1 -name '*.img' -newer "$PICORE_IMG" | head -1)
|
|
if [ -n "$EXTRACTED_IMG" ] && [ "$EXTRACTED_IMG" != "$PICORE_RAW" ]; then
|
|
mv "$EXTRACTED_IMG" "$PICORE_RAW"
|
|
fi
|
|
;;
|
|
*.img.gz)
|
|
gunzip -k "$PICORE_IMG" 2>/dev/null || \
|
|
zcat "$PICORE_IMG" > "$PICORE_RAW"
|
|
;;
|
|
*)
|
|
echo "ERROR: Unknown piCore image format: $PICORE_IMG"
|
|
exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
# Mount the piCore boot partition (partition 1) to find kernel/initramfs
|
|
# piCore layout: p1=boot (FAT32, has kernel+initramfs), p2=rootfs (ext4, has tce/)
|
|
IMG_MNT=$(mktemp -d)
|
|
echo " Mounting piCore boot partition..."
|
|
|
|
# Get partition 1 offset (boot/FAT partition with kernel+initramfs)
|
|
OFFSET=$(fdisk -l "$PICORE_RAW" 2>/dev/null | awk '/^.*img1/{print $2}')
|
|
if [ -z "$OFFSET" ]; then
|
|
# Fallback: try sfdisk (first partition)
|
|
OFFSET=$(sfdisk -d "$PICORE_RAW" 2>/dev/null | awk -F'[=,]' '/start=/{print $2; exit}' | tr -d ' ')
|
|
fi
|
|
if [ -z "$OFFSET" ]; then
|
|
echo "ERROR: Could not determine partition offset in piCore image"
|
|
fdisk -l "$PICORE_RAW" || true
|
|
exit 1
|
|
fi
|
|
|
|
BYTE_OFFSET=$((OFFSET * 512))
|
|
mount -o loop,ro,offset="$BYTE_OFFSET" "$PICORE_RAW" "$IMG_MNT" || {
|
|
echo "ERROR: Failed to mount piCore boot partition (need root for losetup)"
|
|
exit 1
|
|
}
|
|
|
|
# Find initramfs in the piCore boot partition
|
|
COREGZ=""
|
|
for f in "$IMG_MNT"/rootfs-piCore64*.gz "$IMG_MNT"/boot/corepure64.gz "$IMG_MNT"/boot/core.gz "$IMG_MNT"/corepure64.gz "$IMG_MNT"/core.gz; do
|
|
[ -f "$f" ] && COREGZ="$f" && break
|
|
done
|
|
|
|
if [ -z "$COREGZ" ]; then
|
|
echo "ERROR: Could not find initramfs in piCore image"
|
|
echo "Contents:"
|
|
ls -la "$IMG_MNT"/
|
|
ls -la "$IMG_MNT"/boot/ 2>/dev/null || true
|
|
umount "$IMG_MNT" 2>/dev/null || true
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> Found initramfs: $COREGZ"
|
|
|
|
# Extract initramfs
|
|
mkdir -p "$ROOTFS_DIR/rootfs"
|
|
cd "$ROOTFS_DIR/rootfs"
|
|
zcat "$COREGZ" | cpio -idm 2>/dev/null
|
|
|
|
# Note: ARM64 kernel comes from build-kernel-arm64.sh, not from piCore
|
|
# We only use piCore for the BusyBox userland
|
|
|
|
cd "$PROJECT_ROOT"
|
|
umount "$IMG_MNT" 2>/dev/null || true
|
|
rm -rf "$IMG_MNT"
|
|
|
|
echo "==> ARM64 rootfs extracted: $ROOTFS_DIR/rootfs"
|
|
echo " Size: $(du -sh "$ROOTFS_DIR/rootfs" | cut -f1)"
|
|
echo "==> Extract complete (ARM64). Kernel will come from build-kernel-arm64.sh"
|
|
exit 0
|
|
fi
|
|
|
|
# =========================================================================
|
|
# x86_64: Tiny Core ISO extraction
|
|
# =========================================================================
|
|
TC_ISO="$CACHE_DIR/$TINYCORE_ISO"
|
|
ISO_MNT="$ROOTFS_DIR/iso-mount"
|
|
|
|
if [ ! -f "$TC_ISO" ]; then
|
|
echo "ERROR: Tiny Core ISO not found: $TC_ISO"
|
|
echo "Run 'make fetch' first."
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$ISO_MNT"
|
|
|
|
# --- Mount ISO and extract kernel + initramfs ---
|
|
echo "==> Mounting ISO: $TC_ISO"
|
|
mount -o loop,ro "$TC_ISO" "$ISO_MNT" 2>/dev/null || {
|
|
# Fallback for non-root: use 7z or bsdtar
|
|
echo " mount failed (need root?), trying bsdtar..."
|
|
mkdir -p "$ISO_MNT"
|
|
bsdtar xf "$TC_ISO" -C "$ISO_MNT" 2>/dev/null || {
|
|
echo " bsdtar failed, trying 7z..."
|
|
7z x -o"$ISO_MNT" "$TC_ISO" >/dev/null 2>&1
|
|
}
|
|
}
|
|
|
|
# Find vmlinuz and core.gz (path varies by Tiny Core version/arch)
|
|
VMLINUZ=""
|
|
COREGZ=""
|
|
for f in "$ISO_MNT"/boot/vmlinuz64 "$ISO_MNT"/boot/vmlinuz; do
|
|
[ -f "$f" ] && VMLINUZ="$f" && break
|
|
done
|
|
for f in "$ISO_MNT"/boot/corepure64.gz "$ISO_MNT"/boot/core.gz; do
|
|
[ -f "$f" ] && COREGZ="$f" && break
|
|
done
|
|
|
|
if [ -z "$VMLINUZ" ] || [ -z "$COREGZ" ]; then
|
|
echo "ERROR: Could not find vmlinuz/core.gz in ISO"
|
|
echo "ISO contents:"
|
|
find "$ISO_MNT" -type f
|
|
umount "$ISO_MNT" 2>/dev/null || true
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> Found kernel: $VMLINUZ"
|
|
echo "==> Found initramfs: $COREGZ"
|
|
|
|
# Copy kernel
|
|
cp "$VMLINUZ" "$ROOTFS_DIR/vmlinuz"
|
|
|
|
# --- Extract initramfs (core.gz → rootfs) ---
|
|
echo "==> Extracting initramfs..."
|
|
mkdir -p "$ROOTFS_DIR/rootfs"
|
|
cd "$ROOTFS_DIR/rootfs"
|
|
zcat "$COREGZ" | cpio -idm 2>/dev/null
|
|
|
|
# Unmount ISO
|
|
cd "$PROJECT_ROOT"
|
|
umount "$ISO_MNT" 2>/dev/null || true
|
|
rm -rf "$ISO_MNT"
|
|
|
|
echo "==> Rootfs extracted: $ROOTFS_DIR/rootfs"
|
|
echo " Size: $(du -sh "$ROOTFS_DIR/rootfs" | cut -f1)"
|
|
echo " Kernel: $ROOTFS_DIR/vmlinuz ($(du -h "$ROOTFS_DIR/vmlinuz" | cut -f1))"
|
|
|
|
# --- Audit kernel config if available ---
|
|
if [ -f "$ROOTFS_DIR/rootfs/proc/config.gz" ]; then
|
|
echo "==> Kernel config found in rootfs, auditing..."
|
|
"$SCRIPT_DIR/../config/kernel-audit.sh" <(zcat "$ROOTFS_DIR/rootfs/proc/config.gz") || true
|
|
fi
|
|
|
|
echo "==> Extract complete."
|