fix(archiso): document/automate block-level USB write to fix ldlinux.c32 error
"failed to load ldlinux.c32" when booting from USB is caused by writing the isohybrid ISO at file level (drag-and-drop, Rufus "ISO" mode, UNetbootin), which destroys the MBR/isolinux layout. The ISO build itself is correct — archiso's bios.syslinux mode installs isolinux.bin + isohdpfx.bin + the c32 modules and applies the isohybrid MBR, and the profile's bootmodes match upstream releng. Add archiso/write-usb.sh: a safe block-level (dd) writer that lists removable disks, refuses partitions and the system/root disk, requires an all-caps YES, unmounts the target, then writes with conv=fsync. build.sh's completion output now points at it and warns that file-level copies cause exactly this error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>main
parent
fb617185df
commit
3b0bf17210
|
|
@ -228,6 +228,23 @@ else
|
|||
echo "No answerfile — guided (manual) installer will start automatically on boot."
|
||||
fi
|
||||
|
||||
# ── How to write the ISO to USB ────────────────────────────────────────────────
|
||||
# This is an isohybrid image: it MUST be written block-for-block. Copying the
|
||||
# file onto a mounted USB, or using Rufus "ISO" mode / UNetbootin, rewrites the
|
||||
# layout and the BIOS bootloader then fails with "failed to load ldlinux.c32".
|
||||
# Glob (not ls) so filenames are handled safely; date-named ISOs sort ascending,
|
||||
# so the last match is the newest build.
|
||||
_isos=("$OUT_DIR"/*.iso)
|
||||
_built_iso="${_isos[-1]}"
|
||||
if [[ -e "$_built_iso" ]]; then
|
||||
echo
|
||||
echo "To write it to a USB stick (block-level — required for BIOS boot):"
|
||||
echo " bash $SCRIPT_DIR/write-usb.sh \"$_built_iso\" /dev/sdX"
|
||||
echo " or directly: sudo dd if=\"$_built_iso\" of=/dev/sdX bs=4M conv=fsync status=progress"
|
||||
echo " Do NOT drag-and-drop the .iso onto the USB, and avoid Rufus 'ISO' mode"
|
||||
echo " (use 'DD' mode) — those cause 'failed to load ldlinux.c32' at boot."
|
||||
fi
|
||||
|
||||
# ── Netboot artifacts ──────────────────────────────────────────────────────────
|
||||
# mkarchiso's 'netboot' build mode (set in profiledef.sh) produces a tarball
|
||||
# containing the kernel, initramfs, and airootfs.sfs ready for HTTP-based PXE
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
#!/usr/bin/env bash
|
||||
# write-usb.sh — write the M-Archy ISO to a USB stick with a raw, block-level copy.
|
||||
#
|
||||
# WHY THIS EXISTS:
|
||||
# The ISO produced by build.sh is an *isohybrid* image: the BIOS bootloader
|
||||
# (isolinux) and its .c32 modules live at fixed offsets referenced by an MBR
|
||||
# embedded in the first sectors. A block-level write (dd) reproduces those
|
||||
# sectors exactly. Copying the .iso file onto a mounted USB, or using Rufus
|
||||
# "ISO" mode / UNetbootin / similar "ISO-to-USB" tools, rewrites the layout and
|
||||
# the firmware then fails at boot with: "failed to load ldlinux.c32".
|
||||
# Writing the whole device verbatim is the only reliable method, and it boots
|
||||
# on both BIOS (isolinux) and UEFI (systemd-boot) machines.
|
||||
#
|
||||
# USAGE:
|
||||
# bash write-usb.sh <iso> <device>
|
||||
# e.g. bash write-usb.sh ~/m-archy-out/m-archy-2026.06.26-x86_64.iso /dev/sdb
|
||||
# Run with the ISO but no device to list candidate removable disks.
|
||||
|
||||
# -e: abort on error; -u: error on unset vars; -o pipefail: catch pipe failures.
|
||||
set -euo pipefail
|
||||
|
||||
ISO="${1:-}"
|
||||
DEV="${2:-}"
|
||||
|
||||
die() { printf '\n Error: %s\n\n' "$1" >&2; exit 1; }
|
||||
|
||||
# List whole disks so the operator can identify the USB stick. RM=1 marks a
|
||||
# removable device, which is almost always the stick (and never the system disk).
|
||||
list_disks() {
|
||||
echo "Block devices on this machine (RM=1 means removable — usually your USB):"
|
||||
lsblk -dn -o NAME,SIZE,TYPE,RM,MODEL \
|
||||
| awk '$3=="disk" {model=""; for(i=5;i<=NF;i++) model=model (i>5?" ":"") $i;
|
||||
printf " /dev/%-8s %7s RM=%s %s\n", $1, $2, $4, model}'
|
||||
}
|
||||
|
||||
[[ -n "$ISO" ]] || { echo "Usage: bash write-usb.sh <iso> <device>"; echo; list_disks; exit 1; }
|
||||
[[ -f "$ISO" ]] || die "ISO not found: $ISO"
|
||||
if [[ -z "$DEV" ]]; then
|
||||
echo "No target device given for ISO: $ISO"; echo; list_disks
|
||||
echo; echo "Re-run as: bash write-usb.sh \"$ISO\" /dev/sdX"; exit 1
|
||||
fi
|
||||
|
||||
# ── Safety checks (this operation is destructive) ─────────────────────────────
|
||||
[[ -b "$DEV" ]] || die "$DEV is not a block device."
|
||||
# Must be a whole disk, not a partition like /dev/sdb1 — dd to a partition would
|
||||
# not produce a bootable stick and could corrupt an existing filesystem.
|
||||
[[ "$(lsblk -dn -o TYPE "$DEV" 2>/dev/null)" == "disk" ]] \
|
||||
|| die "$DEV is not a whole disk. Pass the disk (e.g. /dev/sdb), not a partition."
|
||||
# Refuse the disk that currently backs the root filesystem — never overwrite the
|
||||
# running system. PKNAME of the root source resolves the parent disk name.
|
||||
_root_src=$(findmnt -no SOURCE / 2>/dev/null || true)
|
||||
_root_disk=$(lsblk -no PKNAME "$_root_src" 2>/dev/null | head -n1 || true)
|
||||
[[ -n "$_root_disk" && "/dev/$_root_disk" == "$DEV" ]] \
|
||||
&& die "$DEV holds your root filesystem — refusing to overwrite the running system."
|
||||
# A non-removable target is suspicious; warn but allow (some USB enclosures
|
||||
# report RM=0). The explicit YES prompt below is the real safeguard.
|
||||
[[ "$(lsblk -dn -o RM "$DEV" 2>/dev/null)" == "1" ]] \
|
||||
|| echo "WARNING: $DEV is NOT flagged removable — make absolutely sure it is your USB stick."
|
||||
|
||||
echo
|
||||
lsblk "$DEV"
|
||||
echo
|
||||
_size=$(lsblk -dn -o SIZE "$DEV")
|
||||
_model=$(lsblk -dn -o MODEL "$DEV" | xargs)
|
||||
echo "About to ERASE $DEV (${_size}${_model:+, $_model}) and write:"
|
||||
echo " $ISO"
|
||||
echo
|
||||
read -rp "Type YES (all caps) to proceed: " _ans
|
||||
[[ "$_ans" == "YES" ]] || { echo "Aborted."; exit 1; }
|
||||
|
||||
# Unmount any mounted partitions of the target so dd has exclusive access.
|
||||
while read -r _part; do
|
||||
sudo umount "/dev/$_part" 2>/dev/null || true
|
||||
done < <(lsblk -ln -o NAME,TYPE "$DEV" | awk '$2=="part"{print $1}')
|
||||
|
||||
echo "Writing (block-level)…"
|
||||
# bs=4M: large blocks for throughput; conv=fsync: flush to the device before dd
|
||||
# exits so "Done" really means written; status=progress: live byte counter.
|
||||
sudo dd if="$ISO" of="$DEV" bs=4M conv=fsync status=progress
|
||||
# Final flush of any remaining kernel buffers for the device.
|
||||
sync
|
||||
|
||||
echo
|
||||
echo "Done — $DEV is now bootable (BIOS + UEFI)."
|
||||
echo "Eject it safely (e.g. 'udisksctl power-off -b $DEV') before unplugging."
|
||||
Loading…
Reference in New Issue