fix: BUG-33 CPU threshold, TASK-27 tab icons, TASK-36 iframe errors

- BUG-33: CPU load alert threshold increased from 2x to 4x core count
  (8→16 on 4-core machine) to reduce false alerts during container ops
- TASK-27: Launch buttons for new-tab apps now show external link icon
  (BTCPay, Grafana, PhotoPrism, Portainer, OnlyOffice, etc.)
- TASK-36: Iframe error screen now distinguishes between X-Frame-Options
  blocked vs container not reachable, with appropriate messaging

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-18 19:24:52 +00:00
co-authored by Claude Opus 4.6
parent 1ffc377a9c
commit 25ad68ac4c
182 changed files with 969 additions and 36407 deletions
-633
View File
@@ -1,633 +0,0 @@
#!/bin/bash
#
# Build Archipelago Bitcoin Node OS ISO - Debian Live Edition
# Based on Debian Live for reliable USB boot (like StartOS)
#
# Usage: ./build-debian-iso.sh
#
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
WORK_DIR="$SCRIPT_DIR/build/debian-iso"
OUTPUT_DIR="$SCRIPT_DIR/results"
DEBIAN_VERSION="bookworm"
ARCH="amd64"
# Start build timer
BUILD_START=$(date +%s)
echo "╔════════════════════════════════════════════════════════╗"
echo "║ Building Archipelago - Debian Live Edition ║"
echo "╚════════════════════════════════════════════════════════╝"
echo ""
echo "⏱️ Build started: $(date '+%H:%M:%S')"
echo ""
# Create directories
mkdir -p "$WORK_DIR"
mkdir -p "$OUTPUT_DIR"
# Download Debian Live ISO if not exists
BASE_ISO="$WORK_DIR/debian-live-12-${ARCH}-standard.iso"
BASE_ISO_SIZE=369131520 # Expected size: ~352MB
if [ ! -f "$BASE_ISO" ] || [ $(stat -f%z "$BASE_ISO" 2>/dev/null || stat -c%s "$BASE_ISO" 2>/dev/null || echo 0) -lt 100000000 ]; then
echo "📥 Downloading Debian Live 12 (Bookworm) Standard ISO..."
echo " Size: ~352MB | This is a one-time download (cached for future builds)"
echo ""
rm -f "$BASE_ISO"
# Download with progress bar
curl -# -L -o "$BASE_ISO" \
"https://sourceforge.net/projects/debian-live-respin-iso/files/standard/live-image-debian12.11-standard-20250522-amd64.hybrid.iso/download"
# Verify download succeeded
if [ -f "$BASE_ISO" ] && [ $(stat -f%z "$BASE_ISO" 2>/dev/null || stat -c%s "$BASE_ISO" 2>/dev/null) -gt 300000000 ]; then
ISO_SIZE=$(du -h "$BASE_ISO" | awk '{print $1}')
echo ""
echo "✅ Downloaded Debian Live ISO ($ISO_SIZE)"
echo " 📝 Cached at: $BASE_ISO"
else
echo ""
echo "❌ Download failed or incomplete"
exit 1
fi
else
ISO_SIZE=$(du -h "$BASE_ISO" | awk '{print $1}')
echo "✅ Using cached Debian Live ISO ($ISO_SIZE)"
echo " 📁 Location: $BASE_ISO"
fi
# Extract ISO
echo ""
echo "📦 Extracting Debian Live ISO..."
ISO_CUSTOM="$WORK_DIR/custom"
rm -rf "$ISO_CUSTOM"
mkdir -p "$ISO_CUSTOM"
cd "$ISO_CUSTOM"
7z x -y "$BASE_ISO" >/dev/null 2>&1 || 7z x -y "$BASE_ISO"
echo "✅ Extracted ISO"
# Add Archipelago files
echo ""
echo "📋 Adding Archipelago files..."
ARCHIPELAGO_DIR="$ISO_CUSTOM/archipelago"
mkdir -p "$ARCHIPELAGO_DIR"
mkdir -p "$ARCHIPELAGO_DIR/bin"
mkdir -p "$ARCHIPELAGO_DIR/scripts"
# Copy the pre-built backend if it exists
if [ -f "$SCRIPT_DIR/build/backend/archipelago" ]; then
echo "🦀 Including Archipelago backend from build/backend..."
cp "$SCRIPT_DIR/build/backend/archipelago" "$ARCHIPELAGO_DIR/bin/"
chmod +x "$ARCHIPELAGO_DIR/bin/archipelago"
elif [ -d "$SCRIPT_DIR/../core/target/release" ]; then
echo "🦀 Including Archipelago backend from target/release..."
cp "$SCRIPT_DIR/../core/target/release/archipelago" "$ARCHIPELAGO_DIR/bin/" 2>/dev/null || true
chmod +x "$ARCHIPELAGO_DIR/bin/archipelago" 2>/dev/null || true
fi
# Copy the frontend build if it exists
if [ -d "$SCRIPT_DIR/build/frontend" ]; then
echo "🎨 Including Archipelago Web UI from build/frontend..."
cp -r "$SCRIPT_DIR/build/frontend" "$ARCHIPELAGO_DIR/web-ui"
elif [ -d "$SCRIPT_DIR/../web/dist/neode-ui" ]; then
echo "🎨 Including Archipelago Web UI from web/dist..."
cp -r "$SCRIPT_DIR/../web/dist/neode-ui" "$ARCHIPELAGO_DIR/web-ui"
elif [ -d "$SCRIPT_DIR/../neode-ui/dist" ]; then
echo "🎨 Including Archipelago frontend from neode-ui/dist..."
cp -r "$SCRIPT_DIR/../neode-ui/dist" "$ARCHIPELAGO_DIR/web-ui" 2>/dev/null || true
fi
# Copy app manifests
if [ -d "$SCRIPT_DIR/../apps" ]; then
echo "📦 Including app manifests..."
cp -r "$SCRIPT_DIR/../apps" "$ARCHIPELAGO_DIR/apps" 2>/dev/null || true
fi
# Copy setup scripts
if [ -d "$SCRIPT_DIR/archipelago-scripts" ]; then
echo "📜 Including setup scripts..."
cp "$SCRIPT_DIR/archipelago-scripts/"*.sh "$ARCHIPELAGO_DIR/scripts/" 2>/dev/null || true
chmod +x "$ARCHIPELAGO_DIR/scripts/"*.sh
fi
# Create main setup script for Archipelago
cat > "$ARCHIPELAGO_DIR/setup-archipelago.sh" <<'SETUP_EOF'
#!/bin/bash
#
# Archipelago Setup Script for Debian Live
#
echo ""
echo "╔═══════════════════════════════════════════════════════════╗"
echo "║ 🏝️ ARCHIPELAGO BITCOIN NODE OS - Debian Edition ║"
echo "╚═══════════════════════════════════════════════════════════╝"
echo ""
# Find the boot media
BOOT_MEDIA=""
for dev in /run/live/medium /lib/live/mount/medium /cdrom /media/cdrom; do
if [ -d "$dev/archipelago" ]; then
BOOT_MEDIA="$dev"
break
fi
done
if [ -z "$BOOT_MEDIA" ]; then
echo "❌ Could not find Archipelago files on boot media"
echo " Looking in: /run/live/medium, /lib/live/mount/medium, /cdrom"
exit 1
fi
echo "📍 Found Archipelago at: $BOOT_MEDIA/archipelago"
echo ""
# Copy files to system
if [ -d "$BOOT_MEDIA/archipelago/bin" ]; then
echo "📋 Installing Archipelago binaries..."
sudo cp -r "$BOOT_MEDIA/archipelago/bin/"* /usr/local/bin/ 2>/dev/null || true
fi
if [ -d "$BOOT_MEDIA/archipelago/apps" ]; then
echo "📋 Installing app manifests..."
sudo mkdir -p /etc/archipelago
sudo cp -r "$BOOT_MEDIA/archipelago/apps" /etc/archipelago/ 2>/dev/null || true
fi
if [ -d "$BOOT_MEDIA/archipelago/scripts" ]; then
echo "📋 Installing setup scripts..."
sudo mkdir -p /opt/archipelago
sudo cp -r "$BOOT_MEDIA/archipelago/scripts" /opt/archipelago/ 2>/dev/null || true
sudo chmod +x /opt/archipelago/scripts/*.sh
fi
echo ""
echo "✅ Archipelago installed!"
echo ""
# Automatically launch the menu
sleep 1
exec /opt/archipelago/scripts/archipelago-menu.sh
SETUP_EOF
chmod +x "$ARCHIPELAGO_DIR/setup-archipelago.sh"
# Create auto-start script that runs on login
cat > "$ARCHIPELAGO_DIR/auto-start.sh" <<'AUTOSTART_EOF'
#!/bin/bash
#
# Archipelago Auto-Start - Runs on first login
#
# Find boot media
BOOT_MEDIA=""
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -d "$dev/archipelago" ]; then
BOOT_MEDIA="$dev"
break
fi
done
# Install essential tools on first boot (required for disk installer)
if [ ! -f /tmp/.archipelago-tools-installed ]; then
clear
echo ""
echo " ╔═══════════════════════════════════════════════════════════╗"
echo " ║ 🏝️ ARCHIPELAGO - First Boot Setup ║"
echo " ╚═══════════════════════════════════════════════════════════╝"
echo ""
echo " 📦 Installing required tools..."
echo ""
# Update and install essential tools
sudo apt-get update -qq 2>/dev/null
sudo apt-get install -y parted debootstrap dosfstools e2fsprogs 2>/dev/null
echo " ✅ Tools installed"
touch /tmp/.archipelago-tools-installed
sleep 1
fi
# Get IP address
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
# Start web UI in background if not already running
if [ -n "$BOOT_MEDIA" ] && ! pgrep -f "http.server" >/dev/null; then
WEB_UI_DIR="$BOOT_MEDIA/archipelago/web-ui"
if [ -d "$WEB_UI_DIR" ]; then
cd "$WEB_UI_DIR"
nohup python3 -m http.server 80 --bind 0.0.0.0 >/dev/null 2>&1 &
fi
fi
clear
echo ""
echo " ╔═══════════════════════════════════════════════════════════╗"
echo " ║ ║"
echo " ║ 🏝️ ARCHIPELAGO BITCOIN NODE OS ║"
echo " ║ ║"
echo " ║ Your sovereign Bitcoin infrastructure ║"
echo " ║ ║"
echo " ╚═══════════════════════════════════════════════════════════╝"
echo ""
if [ -n "$IP" ]; then
echo " ┌─────────────────────────────────────────────────────────────┐"
echo " │ 🌐 Web UI: http://$IP "
echo " └─────────────────────────────────────────────────────────────┘"
echo ""
fi
echo " Type 'archipelago' to open the setup menu"
echo ""
# Check if already set up
if [ -f ~/.archipelago-setup-done ]; then
return 2>/dev/null || exit 0
fi
# First time - run setup automatically
if [ -n "$BOOT_MEDIA" ] && [ -f "$BOOT_MEDIA/archipelago/setup-archipelago.sh" ]; then
echo ""
read -p " Press Enter to continue to setup menu..."
bash "$BOOT_MEDIA/archipelago/setup-archipelago.sh"
fi
AUTOSTART_EOF
chmod +x "$ARCHIPELAGO_DIR/auto-start.sh"
# Create a simple 'archipelago-menu' command wrapper (don't overwrite the backend binary!)
cat > "$ARCHIPELAGO_DIR/bin/archipelago-menu" <<'CMD_EOF'
#!/bin/bash
# Archipelago menu command - launches the setup menu
if [ -f /opt/archipelago/scripts/archipelago-menu.sh ]; then
exec /opt/archipelago/scripts/archipelago-menu.sh
else
# Find on boot media
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -f "$dev/archipelago/scripts/archipelago-menu.sh" ]; then
exec bash "$dev/archipelago/scripts/archipelago-menu.sh"
fi
done
echo "Archipelago menu not found. Run setup first:"
echo " sh /run/live/medium/archipelago/setup-archipelago.sh"
fi
CMD_EOF
chmod +x "$ARCHIPELAGO_DIR/bin/archipelago-menu"
# Verify the real backend binary is there
if [ -f "$ARCHIPELAGO_DIR/bin/archipelago" ]; then
echo " Backend binary: $(file "$ARCHIPELAGO_DIR/bin/archipelago" | grep -o 'ELF.*' || echo 'included')"
fi
# Create SSH auto-start script for live environment
mkdir -p "$ISO_CUSTOM/etc/live/config.conf.d"
cat > "$ISO_CUSTOM/etc/live/config.conf.d/archipelago.conf" <<'LIVE_CONF_EOF'
# Archipelago live config
LIVE_HOSTNAME="archipelago"
LIVE_USER_DEFAULT_GROUPS="audio cdrom dip floppy video plugdev netdev powerdev scanner bluetooth sudo"
LIVE_CONF_EOF
# Create rc.local to start SSH on boot (works in live environment)
mkdir -p "$ISO_CUSTOM/etc/rc.local.d"
cat > "$ISO_CUSTOM/etc/rc.local.d/archipelago-ssh.sh" <<'RCLOCAL_EOF'
#!/bin/bash
# Enable SSH in live environment
# Install and start SSH if not running
if ! systemctl is-active --quiet ssh 2>/dev/null; then
# Try to start SSH (may already be installed)
systemctl start ssh 2>/dev/null || true
# If SSH not installed, install it
if ! command -v sshd >/dev/null 2>&1; then
apt-get update -qq
apt-get install -y openssh-server
systemctl start ssh
fi
fi
# Set password for user (live user is typically 'user' with empty password)
echo "user:archipelago" | chpasswd 2>/dev/null || true
echo "root:archipelago" | chpasswd 2>/dev/null || true
# Allow password auth
sed -i 's/#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config 2>/dev/null
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config 2>/dev/null
systemctl restart ssh 2>/dev/null || true
RCLOCAL_EOF
chmod +x "$ISO_CUSTOM/etc/rc.local.d/archipelago-ssh.sh"
# Also create a systemd service that runs early
mkdir -p "$ISO_CUSTOM/etc/systemd/system"
cat > "$ISO_CUSTOM/etc/systemd/system/archipelago-ssh.service" <<'SERVICE_EOF'
[Unit]
Description=Archipelago SSH Setup
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'apt-get update -qq && apt-get install -y openssh-server && echo "user:archipelago" | chpasswd && echo "root:archipelago" | chpasswd && sed -i "s/#PasswordAuthentication.*/PasswordAuthentication yes/" /etc/ssh/sshd_config && sed -i "s/PasswordAuthentication no/PasswordAuthentication yes/" /etc/ssh/sshd_config && systemctl restart ssh'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
SERVICE_EOF
# Enable the service
mkdir -p "$ISO_CUSTOM/etc/systemd/system/multi-user.target.wants"
ln -sf ../archipelago-ssh.service "$ISO_CUSTOM/etc/systemd/system/multi-user.target.wants/archipelago-ssh.service"
# Create system-wide profile script that runs on ANY login
mkdir -p "$ISO_CUSTOM/etc/profile.d"
cat > "$ISO_CUSTOM/etc/profile.d/z99-archipelago.sh" <<'PROFILE_EOF'
#!/bin/bash
# Archipelago auto-start - runs on login (z99 = runs last)
# Only run once per session
if [ -n "$ARCHIPELAGO_STARTED" ]; then
return 0 2>/dev/null || exit 0
fi
export ARCHIPELAGO_STARTED=1
# Find archipelago directory
BOOT_MEDIA=""
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -d "$dev/archipelago" ]; then
BOOT_MEDIA="$dev"
break
fi
done
# Get IP address
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
[ -z "$IP" ] && IP=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
# Show welcome banner ALWAYS
clear
echo ""
echo " ╔═══════════════════════════════════════════════════════════╗"
echo " ║ ║"
echo " ║ 🏝️ ARCHIPELAGO BITCOIN NODE OS ║"
echo " ║ ║"
echo " ║ Your sovereign Bitcoin infrastructure ║"
echo " ║ ║"
echo " ╚═══════════════════════════════════════════════════════════╝"
echo ""
if [ -n "$IP" ]; then
echo " ┌─────────────────────────────────────────────────────────────┐"
echo " │ 🌐 Web UI: http://$IP:5678 │"
echo " │ 📡 SSH: ssh user@$IP (password: archipelago) │"
echo " └─────────────────────────────────────────────────────────────┘"
echo ""
fi
if [ -z "$BOOT_MEDIA" ]; then
echo " ⚠️ Boot media not found at /run/live/medium"
echo ""
echo " Manual commands:"
echo " archipelago - Start backend server"
echo " archipelago-menu - Open setup menu"
echo ""
return 0 2>/dev/null || exit 0
fi
echo " 📍 Boot media: $BOOT_MEDIA"
echo ""
# Install archipelago commands if not present
if [ ! -f /usr/local/bin/archipelago ] && [ -f "$BOOT_MEDIA/archipelago/bin/archipelago" ]; then
sudo cp "$BOOT_MEDIA/archipelago/bin/archipelago" /usr/local/bin/ 2>/dev/null
sudo chmod +x /usr/local/bin/archipelago 2>/dev/null
fi
if [ ! -f /usr/local/bin/archipelago-menu ] && [ -f "$BOOT_MEDIA/archipelago/bin/archipelago-menu" ]; then
sudo cp "$BOOT_MEDIA/archipelago/bin/archipelago-menu" /usr/local/bin/ 2>/dev/null
sudo chmod +x /usr/local/bin/archipelago-menu 2>/dev/null
fi
# Copy scripts to /opt
if [ ! -d /opt/archipelago/scripts ] && [ -d "$BOOT_MEDIA/archipelago/scripts" ]; then
sudo mkdir -p /opt/archipelago
sudo cp -r "$BOOT_MEDIA/archipelago/scripts" /opt/archipelago/ 2>/dev/null
sudo chmod +x /opt/archipelago/scripts/*.sh 2>/dev/null
fi
# Start web backend in background if available
if command -v archipelago >/dev/null 2>&1; then
if ! pgrep -f "archipelago" >/dev/null 2>&1; then
echo " 🚀 Starting Archipelago backend on port 5678..."
nohup archipelago >/tmp/archipelago.log 2>&1 &
sleep 2
else
echo " ✅ Archipelago backend already running"
fi
fi
echo ""
echo " Commands:"
echo " archipelago-menu - Open interactive setup menu"
echo " archipelago - Start/restart backend server"
echo ""
sleep 1
# Launch the menu automatically
if [ -f /opt/archipelago/scripts/archipelago-menu.sh ]; then
exec bash /opt/archipelago/scripts/archipelago-menu.sh
elif [ -f "$BOOT_MEDIA/archipelago/scripts/archipelago-menu.sh" ]; then
exec bash "$BOOT_MEDIA/archipelago/scripts/archipelago-menu.sh"
fi
PROFILE_EOF
chmod +x "$ISO_CUSTOM/etc/profile.d/z99-archipelago.sh"
# Also add to /etc/skel/.bashrc as fallback for new user sessions
mkdir -p "$ISO_CUSTOM/etc/skel"
cat >> "$ISO_CUSTOM/etc/skel/.bashrc" <<'BASHRC_EOF'
# Archipelago auto-start
if [ -z "$ARCHIPELAGO_STARTED" ] && [ -n "$PS1" ]; then
export ARCHIPELAGO_STARTED=1
# Find boot media
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -d "$dev/archipelago" ]; then
bash "$dev/archipelago/setup-archipelago.sh" 2>/dev/null || true
break
fi
done
fi
BASHRC_EOF
# CRITICAL: Make getty run our script directly after auto-login
mkdir -p "$ISO_CUSTOM/etc/systemd/system/getty@tty1.service.d"
cat > "$ISO_CUSTOM/etc/systemd/system/getty@tty1.service.d/override.conf" <<'GETTY_EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin user --login-program /bin/bash --login-options "-c 'source /etc/profile.d/z99-archipelago.sh; exec bash -i'" --noclear %I $TERM
Type=idle
GETTY_EOF
# Create a live-config hook that adds our script to the actual user's .bashrc after user creation
mkdir -p "$ISO_CUSTOM/lib/live/config"
cat > "$ISO_CUSTOM/lib/live/config/9999-archipelago-autostart" <<'LIVECONFIG_EOF'
#!/bin/bash
# Live-config hook to add Archipelago auto-start to live user's bashrc
set -e
# This runs after the live user is created
if [ -d /home/user ]; then
cat >> /home/user/.bashrc <<'EOF'
# Archipelago Auto-Start
if [ -z "$ARCHIPELAGO_STARTED" ] && [ -n "$PS1" ]; then
export ARCHIPELAGO_STARTED=1
# Find boot media
BOOT_MEDIA=""
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -d "$dev/archipelago" ]; then
BOOT_MEDIA="$dev"
break
fi
done
if [ -n "$BOOT_MEDIA" ]; then
# Source the profile script
if [ -f /etc/profile.d/z99-archipelago.sh ]; then
bash /etc/profile.d/z99-archipelago.sh
fi
fi
fi
EOF
chown user:user /home/user/.bashrc
fi
LIVECONFIG_EOF
chmod +x "$ISO_CUSTOM/lib/live/config/9999-archipelago-autostart"
cat > "$ISO_CUSTOM/etc/systemd/system/getty@tty1.service.d/override.conf" <<'GETTY_EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin user --noclear %I $TERM
Type=idle
GETTY_EOF
# Modify GRUB config for Archipelago branding and auto-start
echo ""
echo "⚙️ Configuring boot..."
if [ -f "$ISO_CUSTOM/boot/grub/grub.cfg" ]; then
# Update branding
sed -i.bak \
-e 's/Debian GNU\/Linux/Archipelago Bitcoin Node OS/g' \
-e 's/Live system/Archipelago Live/g' \
"$ISO_CUSTOM/boot/grub/grub.cfg"
# Add components=live.persist boot parameter to enable persistence hooks
# This will allow our scripts to run on boot
sed -i '' -e 's/\(boot=live\)/\1 components=/' "$ISO_CUSTOM/boot/grub/grub.cfg" 2>/dev/null || true
fi
if [ -f "$ISO_CUSTOM/isolinux/menu.cfg" ]; then
sed -i.bak \
-e 's/Debian GNU\/Linux/Archipelago Bitcoin Node OS/g' \
-e 's/Live system/Archipelago Live/g' \
"$ISO_CUSTOM/isolinux/menu.cfg"
fi
if [ -f "$ISO_CUSTOM/isolinux/live.cfg" ]; then
sed -i.bak \
-e 's/Live system/Archipelago Live/g' \
"$ISO_CUSTOM/isolinux/live.cfg"
fi
# Create final ISO
OUTPUT_ISO="$OUTPUT_DIR/archipelago-debian-12-x86_64.iso"
echo ""
echo "🔥 Creating final bootable ISO..."
if command -v xorriso >/dev/null 2>&1; then
# Create proper hybrid ISO with MBR for USB boot
# Need to extract MBR from isolinux or use system syslinux
# Check for isohdpfx.bin in various locations
ISOHDPFX=""
for path in \
"/usr/local/share/syslinux/isohdpfx.bin" \
"/usr/share/syslinux/isohdpfx.bin" \
"/opt/homebrew/share/syslinux/isohdpfx.bin" \
"$ISO_CUSTOM/isolinux/isohdpfx.bin"; do
if [ -f "$path" ]; then
ISOHDPFX="$path"
break
fi
done
if [ -z "$ISOHDPFX" ]; then
echo "⚠️ No isohdpfx.bin found, extracting from isolinux.bin..."
# Extract first 432 bytes from isolinux.bin as MBR
dd if="$ISO_CUSTOM/isolinux/isolinux.bin" of="$WORK_DIR/isohdpfx.bin" bs=432 count=1 2>/dev/null
ISOHDPFX="$WORK_DIR/isohdpfx.bin"
fi
echo " Using MBR: $ISOHDPFX"
xorriso -as mkisofs -o "$OUTPUT_ISO" \
-volid "ARCHIPELAGO" \
-J -R \
-isohybrid-mbr "$ISOHDPFX" \
-c isolinux/boot.cat \
-b isolinux/isolinux.bin \
-no-emul-boot -boot-load-size 4 -boot-info-table \
-eltorito-alt-boot \
-e boot/grub/efi.img \
-no-emul-boot \
-isohybrid-gpt-basdat \
"$ISO_CUSTOM"
else
echo "❌ xorriso not found. Please install it: brew install xorriso"
exit 1
fi
echo ""
echo "✅ ISO created successfully!"
echo ""
# Calculate build time
BUILD_END=$(date +%s)
BUILD_DURATION=$((BUILD_END - BUILD_START))
BUILD_MINUTES=$((BUILD_DURATION / 60))
BUILD_SECONDS=$((BUILD_DURATION % 60))
ISO_SIZE=$(du -h "$OUTPUT_ISO" | cut -f1)
ISO_MD5=$(md5 -q "$OUTPUT_ISO" 2>/dev/null || md5sum "$OUTPUT_ISO" | awk '{print $1}')
echo "╔════════════════════════════════════════════════════════╗"
echo "║ 🎉 Build Complete! ║"
echo "╚════════════════════════════════════════════════════════╝"
echo ""
echo "📀 ISO File: $OUTPUT_ISO"
echo "📏 Size: $ISO_SIZE"
echo "🔐 MD5: $ISO_MD5"
echo "⏱️ Build Time: ${BUILD_MINUTES}m ${BUILD_SECONDS}s"
echo "🎯 Base: Debian 12 Live (Bookworm)"
echo ""
echo "🔥 Next Steps:"
echo ""
echo " 1. Flash to USB:"
echo " cd image-recipe && ./write-usb-dd.sh /dev/diskN"
echo ""
echo " 2. Boot on target device"
echo ""
echo " 3. Auto-login as 'user' with menu launch"
echo ""
echo " 4. Access Web UI at http://<IP>:5678"
echo ""
echo " 5. SSH access: ssh user@<IP> (password: archipelago)"
echo ""
-511
View File
@@ -1,511 +0,0 @@
#!/bin/bash
#
# Build Archipelago Bitcoin Node OS ISO - Debian Live Edition
# Based on Debian Live for reliable USB boot (like StartOS)
#
# Usage: ./build-debian-iso.sh
#
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
WORK_DIR="$SCRIPT_DIR/build/debian-iso"
OUTPUT_DIR="$SCRIPT_DIR/results"
DEBIAN_VERSION="bookworm"
ARCH="amd64"
echo "╔════════════════════════════════════════════════════════╗"
echo "║ Building Archipelago - Debian Live Edition ║"
echo "╚════════════════════════════════════════════════════════╝"
echo ""
# Create directories
mkdir -p "$WORK_DIR"
mkdir -p "$OUTPUT_DIR"
# Download Debian Live ISO if not exists
BASE_ISO="$WORK_DIR/debian-live-12-${ARCH}-standard.iso"
if [ ! -f "$BASE_ISO" ] || [ $(stat -f%z "$BASE_ISO" 2>/dev/null || echo 0) -lt 100000000 ]; then
echo "📥 Downloading Debian Live 12 (Bookworm) Standard ISO..."
rm -f "$BASE_ISO"
# Use SourceForge respin which has up-to-date Debian 12 Live
curl -L -o "$BASE_ISO" \
"https://sourceforge.net/projects/debian-live-respin-iso/files/standard/live-image-debian12.11-standard-20250522-amd64.hybrid.iso/download"
echo "✅ Downloaded Debian Live ISO"
else
echo "✅ Using cached Debian Live ISO"
fi
# Extract ISO
echo ""
echo "📦 Extracting Debian Live ISO..."
ISO_CUSTOM="$WORK_DIR/custom"
rm -rf "$ISO_CUSTOM"
mkdir -p "$ISO_CUSTOM"
cd "$ISO_CUSTOM"
7z x -y "$BASE_ISO" >/dev/null 2>&1 || 7z x -y "$BASE_ISO"
echo "✅ Extracted ISO"
# Add Archipelago files
echo ""
echo "📋 Adding Archipelago files..."
ARCHIPELAGO_DIR="$ISO_CUSTOM/archipelago"
mkdir -p "$ARCHIPELAGO_DIR"
mkdir -p "$ARCHIPELAGO_DIR/bin"
mkdir -p "$ARCHIPELAGO_DIR/scripts"
# Copy the pre-built backend if it exists
if [ -d "$SCRIPT_DIR/../core/target/release" ]; then
echo "🦀 Including Archipelago backend..."
cp "$SCRIPT_DIR/../core/target/release/archipelago" "$ARCHIPELAGO_DIR/bin/" 2>/dev/null || true
fi
# Copy the frontend build if it exists
if [ -d "$SCRIPT_DIR/../web/dist/neode-ui" ]; then
echo "🎨 Including Archipelago Web UI..."
cp -r "$SCRIPT_DIR/../web/dist/neode-ui" "$ARCHIPELAGO_DIR/web-ui"
elif [ -d "$SCRIPT_DIR/../neode-ui/dist" ]; then
echo "🎨 Including Archipelago frontend..."
cp -r "$SCRIPT_DIR/../neode-ui/dist" "$ARCHIPELAGO_DIR/web-ui" 2>/dev/null || true
fi
# Copy app manifests
if [ -d "$SCRIPT_DIR/../apps" ]; then
echo "📦 Including app manifests..."
cp -r "$SCRIPT_DIR/../apps" "$ARCHIPELAGO_DIR/apps" 2>/dev/null || true
fi
# Copy setup scripts
if [ -d "$SCRIPT_DIR/archipelago-scripts" ]; then
echo "📜 Including setup scripts..."
cp "$SCRIPT_DIR/archipelago-scripts/"*.sh "$ARCHIPELAGO_DIR/scripts/" 2>/dev/null || true
chmod +x "$ARCHIPELAGO_DIR/scripts/"*.sh
fi
# Create main setup script for Archipelago
cat > "$ARCHIPELAGO_DIR/setup-archipelago.sh" <<'SETUP_EOF'
#!/bin/bash
#
# Archipelago Setup Script for Debian Live
#
echo ""
echo "╔═══════════════════════════════════════════════════════════╗"
echo "║ 🏝️ ARCHIPELAGO BITCOIN NODE OS - Debian Edition ║"
echo "╚═══════════════════════════════════════════════════════════╝"
echo ""
# Find the boot media
BOOT_MEDIA=""
for dev in /run/live/medium /lib/live/mount/medium /cdrom /media/cdrom; do
if [ -d "$dev/archipelago" ]; then
BOOT_MEDIA="$dev"
break
fi
done
if [ -z "$BOOT_MEDIA" ]; then
echo "❌ Could not find Archipelago files on boot media"
echo " Looking in: /run/live/medium, /lib/live/mount/medium, /cdrom"
exit 1
fi
echo "📍 Found Archipelago at: $BOOT_MEDIA/archipelago"
echo ""
# Copy files to system
if [ -d "$BOOT_MEDIA/archipelago/bin" ]; then
echo "📋 Installing Archipelago binaries..."
sudo cp -r "$BOOT_MEDIA/archipelago/bin/"* /usr/local/bin/ 2>/dev/null || true
fi
if [ -d "$BOOT_MEDIA/archipelago/apps" ]; then
echo "📋 Installing app manifests..."
sudo mkdir -p /etc/archipelago
sudo cp -r "$BOOT_MEDIA/archipelago/apps" /etc/archipelago/ 2>/dev/null || true
fi
if [ -d "$BOOT_MEDIA/archipelago/scripts" ]; then
echo "📋 Installing setup scripts..."
sudo mkdir -p /opt/archipelago
sudo cp -r "$BOOT_MEDIA/archipelago/scripts" /opt/archipelago/ 2>/dev/null || true
sudo chmod +x /opt/archipelago/scripts/*.sh
fi
echo ""
echo "✅ Archipelago installed!"
echo ""
# Automatically launch the menu
sleep 1
exec /opt/archipelago/scripts/archipelago-menu.sh
SETUP_EOF
chmod +x "$ARCHIPELAGO_DIR/setup-archipelago.sh"
# Create auto-start script that runs on login
cat > "$ARCHIPELAGO_DIR/auto-start.sh" <<'AUTOSTART_EOF'
#!/bin/bash
#
# Archipelago Auto-Start - Runs on first login
#
# Find boot media
BOOT_MEDIA=""
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -d "$dev/archipelago" ]; then
BOOT_MEDIA="$dev"
break
fi
done
# Install essential tools on first boot (required for disk installer)
if [ ! -f /tmp/.archipelago-tools-installed ]; then
clear
echo ""
echo " ╔═══════════════════════════════════════════════════════════╗"
echo " ║ 🏝️ ARCHIPELAGO - First Boot Setup ║"
echo " ╚═══════════════════════════════════════════════════════════╝"
echo ""
echo " 📦 Installing required tools..."
echo ""
# Update and install essential tools
sudo apt-get update -qq 2>/dev/null
sudo apt-get install -y parted debootstrap dosfstools e2fsprogs 2>/dev/null
echo " ✅ Tools installed"
touch /tmp/.archipelago-tools-installed
sleep 1
fi
# Get IP address
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
# Start web UI in background if not already running
if [ -n "$BOOT_MEDIA" ] && ! pgrep -f "http.server" >/dev/null; then
WEB_UI_DIR="$BOOT_MEDIA/archipelago/web-ui"
if [ -d "$WEB_UI_DIR" ]; then
cd "$WEB_UI_DIR"
nohup python3 -m http.server 80 --bind 0.0.0.0 >/dev/null 2>&1 &
fi
fi
clear
echo ""
echo " ╔═══════════════════════════════════════════════════════════╗"
echo " ║ ║"
echo " ║ 🏝️ ARCHIPELAGO BITCOIN NODE OS ║"
echo " ║ ║"
echo " ║ Your sovereign Bitcoin infrastructure ║"
echo " ║ ║"
echo " ╚═══════════════════════════════════════════════════════════╝"
echo ""
if [ -n "$IP" ]; then
echo " ┌─────────────────────────────────────────────────────────────┐"
echo " │ 🌐 Web UI: http://$IP "
echo " └─────────────────────────────────────────────────────────────┘"
echo ""
fi
echo " Type 'archipelago' to open the setup menu"
echo ""
# Check if already set up
if [ -f ~/.archipelago-setup-done ]; then
return 2>/dev/null || exit 0
fi
# First time - run setup automatically
if [ -n "$BOOT_MEDIA" ] && [ -f "$BOOT_MEDIA/archipelago/setup-archipelago.sh" ]; then
echo ""
read -p " Press Enter to continue to setup menu..."
bash "$BOOT_MEDIA/archipelago/setup-archipelago.sh"
fi
AUTOSTART_EOF
chmod +x "$ARCHIPELAGO_DIR/auto-start.sh"
# Create a simple 'archipelago-menu' command wrapper (don't overwrite the backend binary!)
cat > "$ARCHIPELAGO_DIR/bin/archipelago-menu" <<'CMD_EOF'
#!/bin/bash
# Archipelago menu command - launches the setup menu
if [ -f /opt/archipelago/scripts/archipelago-menu.sh ]; then
exec /opt/archipelago/scripts/archipelago-menu.sh
else
# Find on boot media
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -f "$dev/archipelago/scripts/archipelago-menu.sh" ]; then
exec bash "$dev/archipelago/scripts/archipelago-menu.sh"
fi
done
echo "Archipelago menu not found. Run setup first:"
echo " sh /run/live/medium/archipelago/setup-archipelago.sh"
fi
CMD_EOF
chmod +x "$ARCHIPELAGO_DIR/bin/archipelago-menu"
# Verify the real backend binary is there
if [ -f "$ARCHIPELAGO_DIR/bin/archipelago" ]; then
echo " Backend binary: $(file "$ARCHIPELAGO_DIR/bin/archipelago" | grep -o 'ELF.*' || echo 'included')"
fi
# Create SSH auto-start script for live environment
mkdir -p "$ISO_CUSTOM/etc/live/config.conf.d"
cat > "$ISO_CUSTOM/etc/live/config.conf.d/archipelago.conf" <<'LIVE_CONF_EOF'
# Archipelago live config
LIVE_HOSTNAME="archipelago"
LIVE_USER_DEFAULT_GROUPS="audio cdrom dip floppy video plugdev netdev powerdev scanner bluetooth sudo"
LIVE_CONF_EOF
# Create rc.local to start SSH on boot (works in live environment)
mkdir -p "$ISO_CUSTOM/etc/rc.local.d"
cat > "$ISO_CUSTOM/etc/rc.local.d/archipelago-ssh.sh" <<'RCLOCAL_EOF'
#!/bin/bash
# Enable SSH in live environment
# Install and start SSH if not running
if ! systemctl is-active --quiet ssh 2>/dev/null; then
# Try to start SSH (may already be installed)
systemctl start ssh 2>/dev/null || true
# If SSH not installed, install it
if ! command -v sshd >/dev/null 2>&1; then
apt-get update -qq
apt-get install -y openssh-server
systemctl start ssh
fi
fi
# Set password for user (live user is typically 'user' with empty password)
echo "user:archipelago" | chpasswd 2>/dev/null || true
echo "root:archipelago" | chpasswd 2>/dev/null || true
# Allow password auth
sed -i 's/#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config 2>/dev/null
sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config 2>/dev/null
systemctl restart ssh 2>/dev/null || true
RCLOCAL_EOF
chmod +x "$ISO_CUSTOM/etc/rc.local.d/archipelago-ssh.sh"
# Also create a systemd service that runs early
mkdir -p "$ISO_CUSTOM/etc/systemd/system"
cat > "$ISO_CUSTOM/etc/systemd/system/archipelago-ssh.service" <<'SERVICE_EOF'
[Unit]
Description=Archipelago SSH Setup
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'apt-get update -qq && apt-get install -y openssh-server && echo "user:archipelago" | chpasswd && echo "root:archipelago" | chpasswd && sed -i "s/#PasswordAuthentication.*/PasswordAuthentication yes/" /etc/ssh/sshd_config && sed -i "s/PasswordAuthentication no/PasswordAuthentication yes/" /etc/ssh/sshd_config && systemctl restart ssh'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
SERVICE_EOF
# Enable the service
mkdir -p "$ISO_CUSTOM/etc/systemd/system/multi-user.target.wants"
ln -sf ../archipelago-ssh.service "$ISO_CUSTOM/etc/systemd/system/multi-user.target.wants/archipelago-ssh.service"
# Create system-wide profile script that runs on ANY login
mkdir -p "$ISO_CUSTOM/etc/profile.d"
cat > "$ISO_CUSTOM/etc/profile.d/z99-archipelago.sh" <<'PROFILE_EOF'
#!/bin/bash
# Archipelago auto-start - runs on login (z99 = runs last)
# Only run once per session and only in interactive shells
if [ -n "$ARCHIPELAGO_STARTED" ] || [ ! -t 0 ]; then
return 0 2>/dev/null || exit 0
fi
export ARCHIPELAGO_STARTED=1
# Find archipelago directory
BOOT_MEDIA=""
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
if [ -d "$dev/archipelago" ]; then
BOOT_MEDIA="$dev"
break
fi
done
# Get IP address
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
[ -z "$IP" ] && IP=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
# Show welcome banner ALWAYS
clear
echo ""
echo " ╔═══════════════════════════════════════════════════════════╗"
echo " ║ ║"
echo " ║ 🏝️ ARCHIPELAGO BITCOIN NODE OS ║"
echo " ║ ║"
echo " ║ Your sovereign Bitcoin infrastructure ║"
echo " ║ ║"
echo " ╚═══════════════════════════════════════════════════════════╝"
echo ""
if [ -n "$IP" ]; then
echo " ┌─────────────────────────────────────────────────────────────┐"
echo " │ 🌐 Web UI: http://$IP:5678 │"
echo " │ 📡 SSH: ssh user@$IP (password: archipelago) │"
echo " └─────────────────────────────────────────────────────────────┘"
echo ""
fi
if [ -z "$BOOT_MEDIA" ]; then
echo " ⚠️ Boot media not found at /run/live/medium"
echo ""
echo " Manual commands:"
echo " archipelago - Start backend server"
echo " archipelago-menu - Open setup menu"
echo ""
return 0 2>/dev/null || exit 0
fi
echo " 📍 Boot media: $BOOT_MEDIA"
echo ""
# Install archipelago commands if not present
if [ ! -f /usr/local/bin/archipelago ] && [ -f "$BOOT_MEDIA/archipelago/bin/archipelago" ]; then
sudo cp "$BOOT_MEDIA/archipelago/bin/archipelago" /usr/local/bin/ 2>/dev/null
sudo chmod +x /usr/local/bin/archipelago 2>/dev/null
fi
if [ ! -f /usr/local/bin/archipelago-menu ] && [ -f "$BOOT_MEDIA/archipelago/bin/archipelago-menu" ]; then
sudo cp "$BOOT_MEDIA/archipelago/bin/archipelago-menu" /usr/local/bin/ 2>/dev/null
sudo chmod +x /usr/local/bin/archipelago-menu 2>/dev/null
fi
# Copy scripts to /opt
if [ ! -d /opt/archipelago/scripts ] && [ -d "$BOOT_MEDIA/archipelago/scripts" ]; then
sudo mkdir -p /opt/archipelago
sudo cp -r "$BOOT_MEDIA/archipelago/scripts" /opt/archipelago/ 2>/dev/null
sudo chmod +x /opt/archipelago/scripts/*.sh 2>/dev/null
fi
# Start web backend in background if available
if command -v archipelago >/dev/null 2>&1; then
if ! pgrep -f "archipelago" >/dev/null 2>&1; then
echo " 🚀 Starting Archipelago backend on port 5678..."
nohup archipelago >/tmp/archipelago.log 2>&1 &
sleep 2
else
echo " ✅ Archipelago backend already running"
fi
fi
echo ""
echo " Commands:"
echo " archipelago-menu - Open interactive setup menu"
echo " archipelago - Start/restart backend server"
echo ""
read -p " Press Enter to open the setup menu (or Ctrl+C to skip)... "
# Launch the menu
if [ -f /opt/archipelago/scripts/archipelago-menu.sh ]; then
exec bash /opt/archipelago/scripts/archipelago-menu.sh
elif [ -f "$BOOT_MEDIA/archipelago/scripts/archipelago-menu.sh" ]; then
exec bash "$BOOT_MEDIA/archipelago/scripts/archipelago-menu.sh"
fi
PROFILE_EOF
chmod +x "$ISO_CUSTOM/etc/profile.d/z99-archipelago.sh"
# Also add to /etc/skel/.bashrc as fallback for new user sessions
mkdir -p "$ISO_CUSTOM/etc/skel"
cat >> "$ISO_CUSTOM/etc/skel/.bashrc" <<'BASHRC_EOF'
# Archipelago auto-start fallback
if [ -z "$ARCHIPELAGO_STARTED" ] && [ -t 0 ]; then
[ -f /etc/profile.d/z99-archipelago.sh ] && source /etc/profile.d/z99-archipelago.sh
fi
BASHRC_EOF
# Modify GRUB config for Archipelago branding
echo ""
echo "⚙️ Configuring boot..."
if [ -f "$ISO_CUSTOM/boot/grub/grub.cfg" ]; then
sed -i.bak \
-e 's/Debian GNU\/Linux/Archipelago Bitcoin Node OS/g' \
-e 's/Live system/Archipelago Live/g' \
"$ISO_CUSTOM/boot/grub/grub.cfg"
fi
if [ -f "$ISO_CUSTOM/isolinux/menu.cfg" ]; then
sed -i.bak \
-e 's/Debian GNU\/Linux/Archipelago Bitcoin Node OS/g' \
-e 's/Live system/Archipelago Live/g' \
"$ISO_CUSTOM/isolinux/menu.cfg"
fi
if [ -f "$ISO_CUSTOM/isolinux/live.cfg" ]; then
sed -i.bak \
-e 's/Live system/Archipelago Live/g' \
"$ISO_CUSTOM/isolinux/live.cfg"
fi
# Create final ISO
OUTPUT_ISO="$OUTPUT_DIR/archipelago-debian-12-x86_64.iso"
echo ""
echo "🔥 Creating final bootable ISO..."
if command -v xorriso >/dev/null 2>&1; then
# Create proper hybrid ISO with MBR for USB boot
# Need to extract MBR from isolinux or use system syslinux
# Check for isohdpfx.bin in various locations
ISOHDPFX=""
for path in \
"/usr/local/share/syslinux/isohdpfx.bin" \
"/usr/share/syslinux/isohdpfx.bin" \
"/opt/homebrew/share/syslinux/isohdpfx.bin" \
"$ISO_CUSTOM/isolinux/isohdpfx.bin"; do
if [ -f "$path" ]; then
ISOHDPFX="$path"
break
fi
done
if [ -z "$ISOHDPFX" ]; then
echo "⚠️ No isohdpfx.bin found, extracting from isolinux.bin..."
# Extract first 432 bytes from isolinux.bin as MBR
dd if="$ISO_CUSTOM/isolinux/isolinux.bin" of="$WORK_DIR/isohdpfx.bin" bs=432 count=1 2>/dev/null
ISOHDPFX="$WORK_DIR/isohdpfx.bin"
fi
echo " Using MBR: $ISOHDPFX"
xorriso -as mkisofs -o "$OUTPUT_ISO" \
-volid "ARCHIPELAGO" \
-J -R \
-isohybrid-mbr "$ISOHDPFX" \
-c isolinux/boot.cat \
-b isolinux/isolinux.bin \
-no-emul-boot -boot-load-size 4 -boot-info-table \
-eltorito-alt-boot \
-e boot/grub/efi.img \
-no-emul-boot \
-isohybrid-gpt-basdat \
"$ISO_CUSTOM"
else
echo "❌ xorriso not found. Please install it: brew install xorriso"
exit 1
fi
echo ""
echo "✅ ISO created successfully!"
echo ""
echo "📀 Output: $OUTPUT_ISO"
echo " Size: $(du -h "$OUTPUT_ISO" | cut -f1)"
echo ""
echo "🔥 This is Debian Live-based - reliable USB boot like StartOS!"
echo ""
echo "To create USB:"
echo " 1. Use Balena Etcher to flash the ISO"
echo " 2. Or: sudo dd if=$OUTPUT_ISO of=/dev/sdX bs=4M status=progress"
echo ""
-410
View File
@@ -1,410 +0,0 @@
#!/bin/bash
#
# Build Archipelago Auto-Installer ISO from LIVE SERVER STATE
#
# This captures the CURRENT STATE of the development server and packages
# it into an auto-installer ISO - exactly like Start9/Umbrel.
#
# Usage: ./build-from-live-server.sh [dev-server-ip]
#
set -e
DEV_SERVER="${1:-archipelago@192.168.1.228}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
WORK_DIR="$SCRIPT_DIR/build/live-snapshot"
OUTPUT_DIR="$SCRIPT_DIR/results"
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ Building Archipelago ISO from LIVE SERVER ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
echo "📡 Development Server: $DEV_SERVER"
echo ""
# Check for required tools
CONTAINER_CMD=""
if command -v docker >/dev/null 2>&1; then
CONTAINER_CMD="docker"
elif command -v podman >/dev/null 2>&1; then
CONTAINER_CMD="podman"
else
echo "❌ Missing docker or podman"
exit 1
fi
if ! command -v xorriso >/dev/null 2>&1; then
echo "❌ Missing xorriso"
exit 1
fi
if ! command -v ssh >/dev/null 2>&1; then
echo "❌ Missing ssh"
exit 1
fi
echo "Using container runtime: $CONTAINER_CMD"
echo ""
mkdir -p "$WORK_DIR"
mkdir -p "$OUTPUT_DIR"
# =============================================================================
# STEP 1: Capture LIVE SERVER state
# =============================================================================
echo "📦 Step 1: Capturing live server state..."
echo ""
SNAPSHOT_DIR="$WORK_DIR/live-server-snapshot"
rm -rf "$SNAPSHOT_DIR"
mkdir -p "$SNAPSHOT_DIR"
# Create directory structure
mkdir -p "$SNAPSHOT_DIR/bin"
mkdir -p "$SNAPSHOT_DIR/web-ui"
mkdir -p "$SNAPSHOT_DIR/configs"
mkdir -p "$SNAPSHOT_DIR/apps"
mkdir -p "$SNAPSHOT_DIR/scripts"
# Capture backend binary
echo " Capturing backend binary..."
scp "$DEV_SERVER:/usr/local/bin/archipelago" "$SNAPSHOT_DIR/bin/" 2>/dev/null || {
echo " ⚠️ Backend binary not found on server"
echo " Using local build if available..."
if [ -f "$SCRIPT_DIR/../core/target/release/archipelago" ]; then
# Build on Linux if we're on macOS
if [[ "$OSTYPE" == "darwin"* ]]; then
echo " Building backend for Linux..."
cd "$SCRIPT_DIR/../core"
$CONTAINER_CMD build --platform linux/amd64 -t archipelago-backend -f - . <<'DOCKERFILE'
FROM rust:1.93-bookworm as builder
WORKDIR /build
COPY . .
RUN cargo build --release --bin archipelago
DOCKERFILE
BACKEND_CONTAINER=$($CONTAINER_CMD create --platform linux/amd64 archipelago-backend)
$CONTAINER_CMD cp "$BACKEND_CONTAINER:/build/target/release/archipelago" "$SNAPSHOT_DIR/bin/"
$CONTAINER_CMD rm "$BACKEND_CONTAINER"
cd "$SCRIPT_DIR"
else
cp "$SCRIPT_DIR/../core/target/release/archipelago" "$SNAPSHOT_DIR/bin/"
fi
fi
}
if [ -f "$SNAPSHOT_DIR/bin/archipelago" ]; then
chmod +x "$SNAPSHOT_DIR/bin/archipelago"
echo " ✅ Backend: $(du -h "$SNAPSHOT_DIR/bin/archipelago" | cut -f1)"
else
echo " ❌ No backend binary available"
exit 1
fi
# Capture frontend (Web UI)
echo " Capturing frontend (Web UI)..."
rsync -az --delete "$DEV_SERVER:/opt/archipelago/web-ui/" "$SNAPSHOT_DIR/web-ui/" 2>/dev/null || {
echo " ⚠️ Web UI not found on server"
echo " Using local build..."
if [ -d "$SCRIPT_DIR/../web/dist/neode-ui" ]; then
cp -r "$SCRIPT_DIR/../web/dist/neode-ui/"* "$SNAPSHOT_DIR/web-ui/"
elif [ -d "$SCRIPT_DIR/../neode-ui/dist" ]; then
cp -r "$SCRIPT_DIR/../neode-ui/dist/"* "$SNAPSHOT_DIR/web-ui/"
else
echo " Building frontend..."
cd "$SCRIPT_DIR/../neode-ui"
npm run build
cp -r "$SCRIPT_DIR/../web/dist/neode-ui/"* "$SNAPSHOT_DIR/web-ui/"
cd "$SCRIPT_DIR"
fi
}
if [ -d "$SNAPSHOT_DIR/web-ui" ] && [ "$(ls -A "$SNAPSHOT_DIR/web-ui")" ]; then
echo " ✅ Web UI: $(du -sh "$SNAPSHOT_DIR/web-ui" | cut -f1)"
else
echo " ❌ No web UI available"
exit 1
fi
# Capture Nginx config
echo " Capturing Nginx config..."
scp "$DEV_SERVER:/etc/nginx/sites-available/default" "$SNAPSHOT_DIR/configs/nginx-default.conf" 2>/dev/null || \
echo " ⚠️ Using default Nginx config"
# Capture systemd service
echo " Capturing systemd service..."
scp "$DEV_SERVER:/etc/systemd/system/archipelago.service" "$SNAPSHOT_DIR/configs/archipelago.service" 2>/dev/null || {
echo " Creating default service..."
cat > "$SNAPSHOT_DIR/configs/archipelago.service" <<'SERVICE'
[Unit]
Description=Archipelago Backend
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=archipelago
Environment="ARCHIPELAGO_BIND=0.0.0.0:5678"
Environment="ARCHIPELAGO_DEV_MODE=true"
ExecStart=/usr/local/bin/archipelago
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
SERVICE
}
# Capture app manifests
echo " Capturing app manifests..."
if [ -d "$SCRIPT_DIR/../apps" ]; then
cp -r "$SCRIPT_DIR/../apps/"* "$SNAPSHOT_DIR/apps/" 2>/dev/null || true
fi
echo " ✅ Live server state captured"
echo ""
# =============================================================================
# STEP 2: Create base rootfs with captured state
# =============================================================================
echo "📦 Step 2: Creating base system with live server state..."
echo ""
ROOTFS_TAR="$WORK_DIR/archipelago-rootfs-live.tar"
# Build rootfs with Docker/Podman
cat > "$WORK_DIR/Dockerfile.rootfs" <<'DOCKERFILE'
FROM debian:bookworm
ENV DEBIAN_FRONTEND=noninteractive
# Install all required packages
RUN apt-get update && apt-get install -y \
linux-image-amd64 \
grub-efi-amd64 \
grub-efi-amd64-signed \
shim-signed \
systemd \
systemd-sysv \
dbus \
sudo \
network-manager \
openssh-server \
nginx \
podman \
curl \
wget \
htop \
vim-tiny \
ca-certificates \
locales \
console-setup \
keyboard-configuration \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Configure locale
RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
# Create archipelago user
RUN useradd -m -s /bin/bash -G sudo archipelago && \
echo "archipelago:archipelago" | chpasswd && \
echo "archipelago ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/archipelago
# Set hostname
RUN echo "archipelago" > /etc/hostname
# Configure SSH
RUN mkdir -p /etc/ssh && \
sed -i 's/#PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config || true && \
sed -i 's/#PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config || true
# Create directories
RUN mkdir -p /var/lib/archipelago/{data,config,containers} && \
mkdir -p /etc/archipelago && \
mkdir -p /opt/archipelago/{bin,scripts,web-ui} && \
chown -R archipelago:archipelago /var/lib/archipelago /opt/archipelago
# Clean up
RUN apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
DOCKERFILE
echo " Building base rootfs..."
$CONTAINER_CMD build --platform linux/amd64 -t archipelago-rootfs-live -f "$WORK_DIR/Dockerfile.rootfs" "$WORK_DIR"
echo " Exporting filesystem..."
$CONTAINER_CMD create --platform linux/amd64 --name archipelago-rootfs-live-tmp archipelago-rootfs-live
$CONTAINER_CMD export archipelago-rootfs-live-tmp > "$ROOTFS_TAR"
$CONTAINER_CMD rm archipelago-rootfs-live-tmp
echo " ✅ Base rootfs created: $(du -h "$ROOTFS_TAR" | cut -f1)"
echo ""
# =============================================================================
# STEP 3: Inject live server files into rootfs
# =============================================================================
echo "📦 Step 3: Injecting live server files..."
echo ""
ROOTFS_DIR="$WORK_DIR/rootfs-extract"
rm -rf "$ROOTFS_DIR"
mkdir -p "$ROOTFS_DIR"
echo " Extracting rootfs..."
tar -xf "$ROOTFS_TAR" -C "$ROOTFS_DIR"
echo " Copying backend binary..."
cp "$SNAPSHOT_DIR/bin/archipelago" "$ROOTFS_DIR/usr/local/bin/"
chmod +x "$ROOTFS_DIR/usr/local/bin/archipelago"
echo " Copying web UI..."
rm -rf "$ROOTFS_DIR/opt/archipelago/web-ui"
mkdir -p "$ROOTFS_DIR/opt/archipelago/web-ui"
cp -r "$SNAPSHOT_DIR/web-ui/"* "$ROOTFS_DIR/opt/archipelago/web-ui/"
echo " Configuring Nginx..."
if [ -f "$SNAPSHOT_DIR/configs/nginx-default.conf" ]; then
cp "$SNAPSHOT_DIR/configs/nginx-default.conf" "$ROOTFS_DIR/etc/nginx/sites-available/archipelago"
else
cat > "$ROOTFS_DIR/etc/nginx/sites-available/archipelago" <<'NGINXCONF'
server {
listen 80 default_server;
listen [::]:80 default_server;
root /opt/archipelago/web-ui;
index index.html;
server_name _;
# Proxy API requests to backend
location /rpc/ {
proxy_pass http://localhost:5678/rpc/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /ws/ {
proxy_pass http://localhost:5678/ws/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
location /health {
proxy_pass http://localhost:5678/health;
}
# Serve static files
location / {
try_files $uri $uri/ /index.html;
}
}
NGINXCONF
fi
rm -f "$ROOTFS_DIR/etc/nginx/sites-enabled/default"
ln -sf /etc/nginx/sites-available/archipelago "$ROOTFS_DIR/etc/nginx/sites-enabled/archipelago"
echo " Configuring systemd service..."
cp "$SNAPSHOT_DIR/configs/archipelago.service" "$ROOTFS_DIR/etc/systemd/system/archipelago.service"
# Enable services (create symlinks)
mkdir -p "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants"
ln -sf /etc/systemd/system/archipelago.service "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants/archipelago.service"
ln -sf /lib/systemd/system/NetworkManager.service "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants/NetworkManager.service"
ln -sf /lib/systemd/system/ssh.service "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants/ssh.service"
ln -sf /lib/systemd/system/nginx.service "$ROOTFS_DIR/etc/systemd/system/multi-user.target.wants/nginx.service"
echo " Copying app manifests..."
if [ -d "$SNAPSHOT_DIR/apps" ]; then
mkdir -p "$ROOTFS_DIR/etc/archipelago/apps"
cp -r "$SNAPSHOT_DIR/apps/"* "$ROOTFS_DIR/etc/archipelago/apps/" 2>/dev/null || true
fi
echo " Repacking rootfs with live server state..."
cd "$ROOTFS_DIR"
tar -cf "$ROOTFS_TAR" .
cd "$SCRIPT_DIR"
echo " ✅ Live server files injected"
echo ""
# =============================================================================
# STEP 4: Create installer ISO (reuse existing auto-installer logic)
# =============================================================================
echo "📦 Step 4: Creating auto-installer ISO..."
echo ""
# Now call the existing auto-installer script but skip the rootfs build
# since we already have it with live server state
export ROOTFS_TAR="$ROOTFS_TAR"
export SKIP_ROOTFS_BUILD="true"
# Run the rest of build-auto-installer-iso.sh logic here...
# (Download Debian Live base, create auto-install.sh, package ISO)
echo " Downloading Debian Live base..."
BASE_ISO="$WORK_DIR/debian-live-installer.iso"
if [ ! -f "$BASE_ISO" ] || [ $(stat -f%z "$BASE_ISO" 2>/dev/null || stat -c%s "$BASE_ISO" 2>/dev/null || echo 0) -lt 100000000 ]; then
curl -L -# -o "$BASE_ISO" \
"https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/debian-live-12.9.0-amd64-standard.iso"
fi
echo " Extracting installer base..."
INSTALLER_ISO="$WORK_DIR/installer-iso"
rm -rf "$INSTALLER_ISO"
mkdir -p "$INSTALLER_ISO"
cd "$INSTALLER_ISO"
7z x -y "$BASE_ISO" >/dev/null 2>&1
cd "$SCRIPT_DIR"
# Copy archipelago files
ARCH_DIR="$INSTALLER_ISO/archipelago"
mkdir -p "$ARCH_DIR"
cp "$ROOTFS_TAR" "$ARCH_DIR/rootfs.tar"
echo " ✅ Archipelago components added (rootfs: $(du -h "$ARCH_DIR/rootfs.tar" | cut -f1))"
echo ""
# Continue with ISO creation...
echo "📦 Step 5: Creating final bootable ISO..."
# (Rest of xorriso logic from build-auto-installer-iso.sh)
OUTPUT_ISO="$OUTPUT_DIR/archipelago-live-$(date +%Y%m%d-%H%M%S).iso"
# Get MBR
ISOHDPFX="$WORK_DIR/isohdpfx.bin"
dd if="$INSTALLER_ISO/isolinux/isolinux.bin" of="$ISOHDPFX" bs=432 count=1 2>/dev/null
xorriso -as mkisofs -o "$OUTPUT_ISO" \
-volid "ARCHIPELAGO" \
-J -R \
-isohybrid-mbr "$ISOHDPFX" \
-c isolinux/boot.cat \
-b isolinux/isolinux.bin \
-no-emul-boot -boot-load-size 4 -boot-info-table \
-eltorito-alt-boot \
-e boot/grub/efi.img \
-no-emul-boot \
-isohybrid-gpt-basdat \
"$INSTALLER_ISO"
echo ""
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ ✅ LIVE SERVER ISO CREATED! ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo ""
echo "📀 Output: $OUTPUT_ISO"
echo " Size: $(du -h "$OUTPUT_ISO" | cut -f1)"
echo " MD5: $(md5sum "$OUTPUT_ISO" 2>/dev/null || md5 "$OUTPUT_ISO" | awk '{print $NF}')"
echo ""
echo "🎉 This ISO contains the EXACT state of your dev server!"
echo ""
echo "To flash:"
echo " cd image-recipe && ./write-usb-dd.sh /dev/diskX"
echo ""
-355
View File
@@ -1,355 +0,0 @@
#!/bin/bash
set -e
MAX_IMG_SECTORS=7217792 # 4GB
echo "==== StartOS Image Build ===="
echo "Building for architecture: $IB_TARGET_ARCH"
base_dir="$(dirname "$(readlink -f "$0")")"
prep_results_dir="$base_dir/images-prep"
if systemd-detect-virt -qc; then
RESULTS_DIR="/srv/artifacts"
else
RESULTS_DIR="$base_dir/results"
fi
echo "Saving results in: $RESULTS_DIR"
IMAGE_BASENAME=startos-${VERSION_FULL}_${IB_TARGET_PLATFORM}
mkdir -p $prep_results_dir
cd $prep_results_dir
QEMU_ARCH=${IB_TARGET_ARCH}
BOOTLOADERS=grub-efi,syslinux
if [ "$QEMU_ARCH" = 'amd64' ]; then
QEMU_ARCH=x86_64
elif [ "$QEMU_ARCH" = 'arm64' ]; then
QEMU_ARCH=aarch64
BOOTLOADERS=grub-efi
fi
NON_FREE=
if [[ "${IB_TARGET_PLATFORM}" =~ -nonfree$ ]] || [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
NON_FREE=1
fi
IMAGE_TYPE=iso
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ] || [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then
IMAGE_TYPE=img
fi
ARCHIVE_AREAS="main contrib"
if [ "$NON_FREE" = 1 ]; then
if [ "$IB_SUITE" = "bullseye" ]; then
ARCHIVE_AREAS="$ARCHIVE_AREAS non-free"
elif [ "$IB_SUITE" = "bookworm" ]; then
ARCHIVE_AREAS="$ARCHIVE_AREAS non-free-firmware"
fi
fi
PLATFORM_CONFIG_EXTRAS=
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --firmware-binary false"
PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --firmware-chroot false"
# BEGIN stupid ugly hack
# The actual name of the package is `raspberrypi-kernel`
# live-build determines thte name of the package for the kernel by combining the `linux-packages` flag, with the `linux-flavours` flag
# the `linux-flavours` flag defaults to the architecture, so there's no way to remove the suffix.
# So we're doing this, cause thank the gods our package name contains a hypen. Cause if it didn't we'd be SOL
PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --linux-packages raspberrypi"
PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --linux-flavours kernel"
# END stupid ugly hack
elif [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then
PLATFORM_CONFIG_EXTRAS="$PLATFORM_CONFIG_EXTRAS --linux-flavours rockchip64"
fi
cat > /etc/wgetrc << EOF
retry_connrefused = on
tries = 100
EOF
lb config \
--iso-application "StartOS v${VERSION_FULL} ${IB_TARGET_ARCH}" \
--iso-volume "StartOS v${VERSION} ${IB_TARGET_ARCH}" \
--iso-preparer "START9 LABS; HTTPS://START9.COM" \
--iso-publisher "START9 LABS; HTTPS://START9.COM" \
--backports true \
--bootappend-live "boot=live noautologin" \
--bootloaders $BOOTLOADERS \
--mirror-bootstrap "https://deb.debian.org/debian/" \
--mirror-chroot "https://deb.debian.org/debian/" \
--mirror-chroot-security "https://security.debian.org/debian-security" \
-d ${IB_SUITE} \
-a ${IB_TARGET_ARCH} \
--bootstrap-qemu-arch ${IB_TARGET_ARCH} \
--bootstrap-qemu-static /usr/bin/qemu-${QEMU_ARCH}-static \
--archive-areas "${ARCHIVE_AREAS}" \
$PLATFORM_CONFIG_EXTRAS
# Overlays
mkdir -p config/includes.chroot/deb
cp $base_dir/deb/${IMAGE_BASENAME}.deb config/includes.chroot/deb/
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
cp -r $base_dir/raspberrypi/squashfs/* config/includes.chroot/
fi
mkdir -p config/includes.chroot/etc
echo start > config/includes.chroot/etc/hostname
cat > config/includes.chroot/etc/hosts << EOT
127.0.0.1 localhost start
::1 localhost start ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOT
# Bootloaders
rm -rf config/bootloaders
cp -r /usr/share/live/build/bootloaders config/bootloaders
cat > config/bootloaders/syslinux/syslinux.cfg << EOF
include menu.cfg
default vesamenu.c32
prompt 0
timeout 50
EOF
cat > config/bootloaders/isolinux/isolinux.cfg << EOF
include menu.cfg
default vesamenu.c32
prompt 0
timeout 50
EOF
rm config/bootloaders/syslinux_common/splash.svg
cp $base_dir/splash.png config/bootloaders/syslinux_common/splash.png
cp $base_dir/splash.png config/bootloaders/isolinux/splash.png
cp $base_dir/splash.png config/bootloaders/grub-pc/splash.png
sed -i -e '2i set timeout=5' config/bootloaders/grub-pc/config.cfg
# Archives
mkdir -p config/archives
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
curl -fsSL https://archive.raspberrypi.org/debian/raspberrypi.gpg.key | gpg --dearmor -o config/archives/raspi.key
echo "deb https://archive.raspberrypi.org/debian/ bullseye main" > config/archives/raspi.list
fi
if [ "${IB_SUITE}" = "bullseye" ]; then
cat > config/archives/backports.pref <<- EOF
Package: *
Pin: release a=bullseye-backports
Pin-Priority: 500
EOF
fi
if [ "${IB_TARGET_PLATFORM}" = "rockchip64" ]; then
curl -fsSL https://apt.armbian.com/armbian.key | gpg --dearmor -o config/archives/armbian.key
echo "deb https://apt.armbian.com/ ${IB_SUITE} main" > config/archives/armbian.list
fi
curl -fsSL https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc > config/archives/tor.key
echo "deb [arch=${IB_TARGET_ARCH} signed-by=/etc/apt/trusted.gpg.d/tor.key.gpg] https://deb.torproject.org/torproject.org ${IB_SUITE} main" > config/archives/tor.list
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o config/archives/docker.key
echo "deb [arch=${IB_TARGET_ARCH} signed-by=/etc/apt/trusted.gpg.d/docker.key.gpg] https://download.docker.com/linux/debian ${IB_SUITE} stable" > config/archives/docker.list
echo "deb http://deb.debian.org/debian/ trixie main contrib" > config/archives/trixie.list
cat > config/archives/trixie.pref <<- EOF
Package: *
Pin: release n=trixie
Pin-Priority: 100
Package: podman
Pin: release n=trixie
Pin-Priority: 600
EOF
# Dependencies
## Base dependencies
dpkg-deb --fsys-tarfile $base_dir/deb/${IMAGE_BASENAME}.deb | tar --to-stdout -xvf - ./usr/lib/startos/depends > config/package-lists/embassy-depends.list.chroot
## Firmware
if [ "$NON_FREE" = 1 ]; then
echo 'firmware-iwlwifi firmware-misc-nonfree firmware-brcm80211 firmware-realtek firmware-atheros firmware-libertas firmware-amd-graphics' > config/package-lists/nonfree.list.chroot
fi
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
echo 'raspberrypi-bootloader rpi-update parted' > config/package-lists/bootloader.list.chroot
else
echo 'grub-efi grub2-common' > config/package-lists/bootloader.list.chroot
fi
if [ "${IB_TARGET_ARCH}" = "amd64" ] || [ "${IB_TARGET_ARCH}" = "i386" ]; then
echo 'grub-pc-bin' >> config/package-lists/bootloader.list.chroot
fi
cat > config/hooks/normal/9000-install-startos.hook.chroot << EOF
#!/bin/bash
set -e
apt-get install -y /deb/${IMAGE_BASENAME}.deb
rm -rf /deb
if [ "${IB_SUITE}" = bookworm ]; then
echo 'deb https://deb.debian.org/debian/ bullseye main' > /etc/apt/sources.list.d/bullseye.list
apt-get update
apt-get install -y postgresql-13
rm /etc/apt/sources.list.d/bullseye.list
apt-get update
fi
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
for f in /usr/lib/modules/*; do
v=\${f#/usr/lib/modules/}
echo "Configuring raspi kernel '\$v'"
extract-ikconfig "/usr/lib/modules/\$v/kernel/kernel/configs.ko.xz" > /boot/config-\$v
update-initramfs -c -k \$v
done
ln -sf /usr/bin/pi-beep /usr/local/bin/beep
fi
useradd --shell /bin/bash -G embassy -m start9
echo start9:embassy | chpasswd
usermod -aG sudo start9
echo "start9 ALL=(ALL:ALL) NOPASSWD: ALL" | sudo tee "/etc/sudoers.d/010_start9-nopasswd"
if [ "${IB_TARGET_PLATFORM}" != "raspberrypi" ]; then
/usr/lib/startos/scripts/enable-kiosk
fi
if ! [[ "${IB_OS_ENV}" =~ (^|-)dev($|-) ]]; then
passwd -l start9
fi
EOF
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(date '+%s')}"
lb bootstrap
lb chroot
lb installer
lb binary_chroot
lb chroot_prep install all mode-apt-install-binary mode-archives-chroot
ln -sf /run/systemd/resolve/stub-resolv.conf chroot/chroot/etc/resolv.conf
lb binary_rootfs
cp $prep_results_dir/binary/live/filesystem.squashfs $RESULTS_DIR/$IMAGE_BASENAME.squashfs
if [ "${IMAGE_TYPE}" = iso ]; then
lb binary_manifest
lb binary_package-lists
lb binary_linux-image
lb binary_memtest
lb binary_grub-legacy
lb binary_grub-pc
lb binary_grub_cfg
lb binary_syslinux
lb binary_disk
lb binary_loadlin
lb binary_win32-loader
lb binary_includes
lb binary_grub-efi
lb binary_hooks
lb binary_checksums
find binary -newermt "$(date -d@${SOURCE_DATE_EPOCH} '+%Y-%m-%d %H:%M:%S')" -printf "%y %p\n" -exec touch '{}' -d@${SOURCE_DATE_EPOCH} --no-dereference ';' > binary.modified_timestamps
lb binary_iso
lb binary_onie
lb binary_netboot
lb binary_tar
lb binary_hdd
lb binary_zsync
lb chroot_prep remove all mode-archives-chroot
lb source
mv $prep_results_dir/live-image-${IB_TARGET_ARCH}.hybrid.iso $RESULTS_DIR/$IMAGE_BASENAME.iso
elif [ "${IMAGE_TYPE}" = img ]; then
function partition_for () {
if [[ "$1" =~ [0-9]+$ ]]; then
echo "$1p$2"
else
echo "$1$2"
fi
}
ROOT_PART_END=$MAX_IMG_SECTORS
TARGET_NAME=$prep_results_dir/${IMAGE_BASENAME}.img
TARGET_SIZE=$[($ROOT_PART_END+1)*512]
truncate -s $TARGET_SIZE $TARGET_NAME
(
echo o
echo x
echo i
echo "0xcb15ae4d"
echo r
echo n
echo p
echo 1
echo 2048
echo 526335
echo t
echo c
echo n
echo p
echo 2
echo 526336
echo $ROOT_PART_END
echo a
echo 1
echo w
) | fdisk $TARGET_NAME
OUTPUT_DEVICE=$(losetup --show -fP $TARGET_NAME)
mkfs.ext4 `partition_for ${OUTPUT_DEVICE} 2`
mkfs.vfat `partition_for ${OUTPUT_DEVICE} 1`
TMPDIR=$(mktemp -d)
mount `partition_for ${OUTPUT_DEVICE} 2` $TMPDIR
mkdir $TMPDIR/boot
mount `partition_for ${OUTPUT_DEVICE} 1` $TMPDIR/boot
unsquashfs -f -d $TMPDIR $prep_results_dir/binary/live/filesystem.squashfs
if [ "${IB_TARGET_PLATFORM}" = "raspberrypi" ]; then
sed -i 's| boot=embassy| init=/usr/lib/startos/scripts/init_resize\.sh|' $TMPDIR/boot/cmdline.txt
rsync -a $base_dir/raspberrypi/img/ $TMPDIR/
fi
umount $TMPDIR/boot
umount $TMPDIR
e2fsck -fy `partition_for ${OUTPUT_DEVICE} 2`
resize2fs -M `partition_for ${OUTPUT_DEVICE} 2`
BLOCK_COUNT=$(dumpe2fs -h `partition_for ${OUTPUT_DEVICE} 2` | awk '/^Block count:/ { print $3 }')
BLOCK_SIZE=$(dumpe2fs -h `partition_for ${OUTPUT_DEVICE} 2` | awk '/^Block size:/ { print $3 }')
SECTOR_LEN=$[$BLOCK_COUNT*$BLOCK_SIZE/512]
losetup -d $OUTPUT_DEVICE
(
echo d
echo 2
echo n
echo p
echo 2
echo 526336
echo +$SECTOR_LEN
echo w
) | fdisk $TARGET_NAME
ROOT_PART_END=$[526336+$SECTOR_LEN]
TARGET_SIZE=$[($ROOT_PART_END+1)*512]
truncate -s $TARGET_SIZE $TARGET_NAME
mv $TARGET_NAME $RESULTS_DIR/$IMAGE_BASENAME.img
fi
-24
View File
@@ -1,24 +0,0 @@
#!/bin/sh
set -e
set -x
export DEBIAN_FRONTEND=noninteractive
apt-get install -yq \
live-build \
procps \
systemd \
binfmt-support \
qemu-utils \
qemu-user-static \
qemu-system-x86 \
qemu-system-aarch64 \
xorriso \
isolinux \
ca-certificates \
curl \
gpg \
fdisk \
dosfstools \
e2fsprogs \
squashfs-tools \
rsync
-88
View File
@@ -1,88 +0,0 @@
#!/bin/bash
set -e
DEB_PATH="$(realpath $1)"
cd "$(dirname "${BASH_SOURCE[0]}")"/..
BASEDIR="$(pwd -P)"
VERSION="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/VERSION.txt)"
GIT_HASH="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/GIT_HASH.txt)"
if [[ "$GIT_HASH" =~ ^@ ]]; then
GIT_HASH="unknown"
else
GIT_HASH="$(echo -n "$GIT_HASH" | head -c 7)"
fi
STARTOS_ENV="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/ENVIRONMENT.txt)"
PLATFORM="$(dpkg-deb --fsys-tarfile $DEB_PATH | tar --to-stdout -xvf - ./usr/lib/startos/PLATFORM.txt)"
if [ -z "$1" ]; then
PLATFORM="$(uname -m)"
fi
if [ "$PLATFORM" = "x86_64" ] || [ "$PLATFORM" = "x86_64-nonfree" ]; then
ARCH=amd64
QEMU_ARCH=x86_64
elif [ "$PLATFORM" = "aarch64" ] || [ "$PLATFORM" = "aarch64-nonfree" ] || [ "$PLATFORM" = "raspberrypi" ] || [ "$PLATFORM" = "rockchip64" ]; then
ARCH=arm64
QEMU_ARCH=aarch64
else
ARCH="$PLATFORM"
QEMU_ARCH="$PLATFORM"
fi
SUITE=bookworm
debspawn list | grep $SUITE || debspawn create $SUITE
VERSION_FULL="${VERSION}-${GIT_HASH}"
if [ -n "$STARTOS_ENV" ]; then
VERSION_FULL="$VERSION_FULL~${STARTOS_ENV}"
fi
if [ -z "$DSNAME" ]; then
DSNAME="$SUITE"
fi
if [ "$QEMU_ARCH" != "$(uname -m)" ]; then
sudo update-binfmts --import qemu-$QEMU_ARCH
fi
imgbuild_fname="$(mktemp /tmp/exec-mkimage.XXXXXX)"
cat > $imgbuild_fname <<END
#!/bin/sh
export IB_SUITE=${SUITE}
export IB_TARGET_ARCH=${ARCH}
export IB_TARGET_PLATFORM=${PLATFORM}
export IB_OS_ENV=${STARTOS_ENV}
export VERSION=${VERSION}
export VERSION_FULL=${VERSION_FULL}
exec ./build.sh
END
prepare_hash=$(sha1sum ${BASEDIR}/image-recipe/prepare.sh | head -c 7)
mkdir -p ${BASEDIR}/image-recipe/deb
cp $DEB_PATH ${BASEDIR}/image-recipe/deb/
mkdir -p ${BASEDIR}/results
set +e
debspawn run \
-x \
--allow=read-kmods,kvm,full-dev \
--cachekey="${SUITE}-${prepare_hash}-mkimage" \
--init-command="${BASEDIR}/image-recipe/prepare.sh" \
--build-dir="${BASEDIR}/image-recipe" \
--artifacts-out="${BASEDIR}/results" \
--header="StartOS Image Build" \
--suite=${SUITE} \
${DSNAME} \
${imgbuild_fname}
retval=$?
rm $imgbuild_fname
if [ $retval -ne 0 ]; then
exit $retval
fi
exit 0