diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 140a95c..bdabac3 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,33 @@ --- +## V39 2026-03-20 23:30:00 + +**Add single-command bootstrap and fix lfs user permission issues** + +### Changes: +- Added `toolchain/bootstrap.sh`: Single entry point that runs the entire Phase 0: + - Tears down and recreates the loopback filesystem (fresh start) + - Sets up environment, downloads sources + - Copies toolchain scripts to `$LFS/sources/toolchain-scripts/` (lfs-accessible) + - Runs `build-all.sh` as lfs user automatically +- Rewrote `toolchain/scripts/000-setup-disk.sh`: + - Now tears down existing build (unmount + delete image) on every run + - No longer exits early if mount exists — always gives a fresh filesystem +- Fixed `toolchain/scripts/build-all.sh`: + - Log directory changed from `${SCRIPT_DIR}/../logs` to `${LFS}/sources/logs/` + - Fixes "Permission denied" when lfs user can't write to danny's home dir + +### Plan deviation/changes: +- Scripts are now copied to `$LFS/sources/toolchain-scripts/` rather than run from + the git repo. This avoids all permission issues with the lfs user not being able + to read /home/danny/. The git repo remains the source of truth. + +### What is missing/needs polish: +- None + +--- + ## V38 2026-03-20 23:00:00 **Sync all Phase 0 build scripts to match Danish mirror tarball versions** diff --git a/toolchain/bootstrap.sh b/toolchain/bootstrap.sh new file mode 100644 index 0000000..63e530c --- /dev/null +++ b/toolchain/bootstrap.sh @@ -0,0 +1,124 @@ +#!/bin/bash +# ============================================================================ +# DarkForge Linux — Phase 0: Full Bootstrap +# ============================================================================ +# Purpose: Single entry point that runs the entire Phase 0 bootstrap: +# 1. Tear down & create fresh loopback filesystem +# 2. Set up directory structure, lfs user, env files +# 3. Download source tarballs +# 4. Copy toolchain scripts to $LFS so lfs user can access them +# 5. Launch build-all.sh as the lfs user +# +# Usage: sudo -E bash toolchain/bootstrap.sh +# (run from the project root, e.g. /home/danny/darkforge) +# +# Inputs: LFS (default: /mnt/darkforge) +# Outputs: A complete cross-toolchain and temporary tools on $LFS +# Assumes: Running as root on Arch Linux, internet access +# ============================================================================ + +set -euo pipefail + +# --- Configuration ----------------------------------------------------------- +export LFS="${LFS:-/mnt/darkforge}" + +# Detect the project root (parent of toolchain/) +BOOTSTRAP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "${BOOTSTRAP_DIR}")" +SCRIPT_SRC="${BOOTSTRAP_DIR}/scripts" + +# Color output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +ok() { echo -e "${GREEN}>>> $*${NC}"; } +warn() { echo -e "${YELLOW}>>> $*${NC}"; } +info() { echo -e "${CYAN}>>> $*${NC}"; } +fail() { echo -e "${RED}>>> $*${NC}"; exit 1; } + +# --- Verify running as root -------------------------------------------------- +[ "$(id -u)" -eq 0 ] || fail "This script must be run as root (use sudo -E)." + +echo "============================================================" +echo " DarkForge Linux — Phase 0 Full Bootstrap" +echo "============================================================" +echo "" +echo " Project root: ${PROJECT_ROOT}" +echo " LFS mount: ${LFS}" +echo "" + +# ============================================================================= +# Step 1: Create fresh loopback filesystem +# ============================================================================= +info "STEP 1/5: Setting up build filesystem..." +bash "${SCRIPT_SRC}/000-setup-disk.sh" +echo "" + +# ============================================================================= +# Step 2: Set up directory structure, lfs user, and env +# ============================================================================= +info "STEP 2/5: Setting up environment..." +bash "${SCRIPT_SRC}/000-env-setup.sh" +echo "" + +# ============================================================================= +# Step 3: Download all source tarballs +# ============================================================================= +info "STEP 3/5: Downloading source tarballs..." +bash "${SCRIPT_SRC}/000a-download-sources.sh" +echo "" + +# ============================================================================= +# Step 4: Copy toolchain scripts to $LFS/sources/toolchain-scripts/ +# ============================================================================= +info "STEP 4/5: Copying toolchain scripts to ${LFS}/sources/toolchain-scripts/..." +SCRIPTS_DEST="${LFS}/sources/toolchain-scripts" +rm -rf "${SCRIPTS_DEST}" +mkdir -p "${SCRIPTS_DEST}" +cp -v "${SCRIPT_SRC}/"*.sh "${SCRIPTS_DEST}/" +chmod +x "${SCRIPTS_DEST}/"*.sh +chown -R lfs:lfs "${SCRIPTS_DEST}" +ok "Scripts copied and owned by lfs user" +echo "" + +# ============================================================================= +# Step 5: Run build-all.sh as lfs user +# ============================================================================= +info "STEP 5/5: Building cross-toolchain as lfs user..." +echo " This will take a while (30-60+ minutes on 32 threads)." +echo " Logs will be in: ${LFS}/sources/logs/" +echo "" + +# Run build-all.sh as the lfs user with a clean environment +# The build scripts source darkforge-env.sh internally, so we just +# need LFS set and the lfs user's PATH to find basic tools. +su -l lfs -c " + export LFS=${LFS} + source ${LFS}/sources/darkforge-env.sh + bash ${SCRIPTS_DEST}/build-all.sh +" || { + fail "Build failed! Check logs in ${LFS}/sources/logs/" +} + +echo "" +echo "============================================================" +echo -e "${GREEN} Phase 0 cross-compilation complete!${NC}" +echo "============================================================" +echo "" +echo "Next steps (run as root):" +echo "" +echo " # Enter the chroot environment:" +echo " sudo -E bash ${SCRIPTS_DEST}/023-chroot-setup.sh" +echo "" +echo " # Then inside chroot, run these in order:" +echo " bash /sources/toolchain-scripts/024-chroot-essentials.sh" +echo " bash /sources/toolchain-scripts/025-gettext.sh" +echo " bash /sources/toolchain-scripts/026-bison.sh" +echo " bash /sources/toolchain-scripts/027-perl.sh" +echo " bash /sources/toolchain-scripts/028-python.sh" +echo " bash /sources/toolchain-scripts/029-texinfo.sh" +echo " bash /sources/toolchain-scripts/030-util-linux.sh" +echo " bash /sources/toolchain-scripts/031-cleanup.sh" diff --git a/toolchain/scripts/000-setup-disk.sh b/toolchain/scripts/000-setup-disk.sh index 30d9e80..dfd6d6c 100755 --- a/toolchain/scripts/000-setup-disk.sh +++ b/toolchain/scripts/000-setup-disk.sh @@ -5,6 +5,7 @@ # Purpose: Create a loopback ext4 filesystem for the LFS build environment. # This avoids repartitioning and uses free space on your root drive. # The loopback file acts exactly like a real partition. +# If a previous build exists, tears it down and starts fresh. # Inputs: None (uses defaults below, override via environment) # Outputs: 50GB ext4 filesystem mounted at /mnt/darkforge # Assumes: Running as root, ~50GB free on root filesystem @@ -39,13 +40,17 @@ echo " Image size: ${LFS_SIZE}" echo " Mount point: ${LFS}" echo "" -# --- Check if already mounted ------------------------------------------------ +# --- Tear down any existing build -------------------------------------------- if mountpoint -q "${LFS}" 2>/dev/null; then - ok "${LFS} is already mounted:" - df -h "${LFS}" - echo "" - echo "To start over: umount ${LFS} && rm ${LFS_IMAGE}" - exit 0 + warn "Existing build found at ${LFS} — tearing down..." + umount -l "${LFS}" 2>/dev/null || true + ok "Unmounted ${LFS}" +fi + +if [ -f "${LFS_IMAGE}" ]; then + warn "Removing old image: ${LFS_IMAGE}" + rm -f "${LFS_IMAGE}" + ok "Old image removed" fi # --- Check free space --------------------------------------------------------- @@ -59,22 +64,17 @@ fi ok "Free space check: ${AVAIL_GB}GB available, need ${NEED_GB}GB" # --- Create the loopback image ----------------------------------------------- -if [ -f "${LFS_IMAGE}" ]; then - warn "Image file already exists: ${LFS_IMAGE}" - echo " Reusing existing image." -else - echo ">>> Creating ${LFS_SIZE} image file (this takes a moment)..." - # Use fallocate for instant allocation (no slow dd) - fallocate -l "${LFS_SIZE}" "${LFS_IMAGE}" || { - warn "fallocate failed, falling back to truncate..." - truncate -s "${LFS_SIZE}" "${LFS_IMAGE}" - } - ok "Image created: ${LFS_IMAGE}" +echo ">>> Creating ${LFS_SIZE} image file..." +# Use fallocate for instant allocation (no slow dd) +fallocate -l "${LFS_SIZE}" "${LFS_IMAGE}" || { + warn "fallocate failed, falling back to truncate..." + truncate -s "${LFS_SIZE}" "${LFS_IMAGE}" +} +ok "Image created: ${LFS_IMAGE}" - echo ">>> Formatting as ext4..." - mkfs.ext4 -q -L darkforge "${LFS_IMAGE}" - ok "Formatted as ext4" -fi +echo ">>> Formatting as ext4..." +mkfs.ext4 -q -L darkforge "${LFS_IMAGE}" +ok "Formatted as ext4" # --- Mount it ----------------------------------------------------------------- mkdir -p "${LFS}" @@ -84,11 +84,7 @@ ok "Mounted ${LFS_IMAGE} at ${LFS}" echo "" df -h "${LFS}" echo "" -ok "LFS build partition is ready." -echo "" -echo "Next steps:" -echo " export LFS=${LFS}" -echo " bash toolchain/scripts/000-env-setup.sh" +ok "LFS build partition is ready (fresh start)." echo "" echo "To remount after reboot:" echo " sudo mount -o loop ${LFS_IMAGE} ${LFS}" diff --git a/toolchain/scripts/build-all.sh b/toolchain/scripts/build-all.sh index f97fcc3..3be058b 100755 --- a/toolchain/scripts/build-all.sh +++ b/toolchain/scripts/build-all.sh @@ -14,7 +14,7 @@ set -euo pipefail LFS="${LFS:-/mnt/darkforge}" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -LOG_DIR="${SCRIPT_DIR}/../logs" +LOG_DIR="${LFS}/sources/logs" mkdir -p "${LOG_DIR}"