Files
hiperiso/scripts/package_release.sh
T
vasilito e79a11bddc fix: rename hlnk->vlnk in grub.cfg + fix mcopy recursion bug
Two critical fixes that unblock the hardlink/chain boot paths:

1. hlnk->vlnk rename in src/grub2/grub/grub.cfg
   The in-tree grub.cfg calls GRUB commands with rebrand 'hlnk' naming
   (vt_is_hlnk_name, vt_get_hlnk_dst, etc.) but the GRUB binary built
   from vendor/grub2-modsrc.tar.xz has Ventoy's original 'vlnk' naming.
   This mismatch caused 'can't find command' errors for any menu item
   using the hardlink path (which is most ISO files).

   Renamed all hlnk references to vlnk in the source grub.cfg.
   Added an automatic hlnk->vlnk sed pass to package_release.sh so
   future edits stay in sync.

2. mcopy recursion bug in package_release.sh
   The single-mcopy optimization (commit 17094e5) used 'mcopy -s -i
   ESP IMG STAGING/* ::/' which only created empty top-level directories
   without copying file contents into them. This meant the deployed
   ESP image had empty EFI/, grub/, hiperiso/ directories.

   Replaced with explicit per-subdirectory copy loop that recursively
   copies each top-level entry with 'mcopy -s -i ESP IMG STAGE/DIR
   ::/DIR'. Verified files are now in the deployed image.

QEMU test confirms:
- Disk boots, GRUB 2.04 loads
- ESP contains BOOTX64.EFI, grub.cfg, ventoy.cpio, chain files
- hlnk/vlnk mismatch fixed: 0 hlnk refs, 20 vlnk refs in grub.cfg
2026-07-02 10:14:35 +03:00

252 lines
13 KiB
Bash
Executable File

#!/bin/sh
set -e
_SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
HIPERISO_ROOT="$(cd "$_SCRIPT_DIR/.." && pwd)"
GRUB2_INSTALL="$HIPERISO_ROOT/build/grub2-204/INSTALL"
PAYLOAD="$HIPERISO_ROOT/build/payload"
STAGING="$HIPERISO_ROOT/build/staging"
_progress() { printf ' \033[1;34m[%d/8]\033[0m %s\n' "$1" "$2"; }
# ── Dependency checks ─────────────────────────────────────────────
command -v mcopy >/dev/null 2>&1 || { echo "ERROR: mtools (mmd/mcopy) required to build ESP image"; exit 1; }
command -v mkfs.vfat >/dev/null 2>&1 || { echo "ERROR: dosfstools (mkfs.vfat) required"; exit 1; }
GRUB_X64_DIR="$HIPERISO_ROOT/build/grub2-204/RUNTIME/grub/x86_64-efi"
[ -d "$GRUB_X64_DIR" ] || GRUB_X64_DIR="$GRUB2_INSTALL/lib/grub/x86_64-efi"
[ -d "$GRUB_X64_DIR" ] || GRUB_X64_DIR="$HIPERISO_ROOT/src/grub2/grub/x86_64-efi"
KERNEL_SRC="$STAGING/efi/vmlinuz"
[ -f "$KERNEL_SRC" ] || KERNEL_SRC="$STAGING/vmlinuz"
EFI_BOOT_SRC="$HIPERISO_ROOT/grub2/bin/BOOTX64.EFI"
[ -f "$EFI_BOOT_SRC" ] || EFI_BOOT_SRC="$STAGING/efi/BOOTX64.EFI"
[ -f "$EFI_BOOT_SRC" ] || EFI_BOOT_SRC="$STAGING/EFI/BOOT/BOOTX64.EFI"
REAL_GRUB_SRC="$HIPERISO_ROOT/grub2/bin/grubx64_real.efi"
[ -f "$REAL_GRUB_SRC" ] || REAL_GRUB_SRC="$STAGING/efi/grubx64_real.efi"
GRUB_EFI_ALIAS_SRC="$HIPERISO_ROOT/grub2/bin/grubx64.efi"
[ -f "$GRUB_EFI_ALIAS_SRC" ] || GRUB_EFI_ALIAS_SRC="$STAGING/efi/grubx64.efi"
SHIM_BOOT_SRC="$HIPERISO_ROOT/vendor/secureboot/BOOTX64.EFI"
[ -f "$SHIM_BOOT_SRC" ] || SHIM_BOOT_SRC="$HIPERISO_ROOT/vendor/secureboot/shimx64.efi"
[ -f "$SHIM_BOOT_SRC" ] || SHIM_BOOT_SRC="$HIPERISO_ROOT/vendor/secureboot/shimx64.efi.signed"
# Clean only subdirectories this script fully repopulates.
# Preserve tool/ (languages.json, HiperisoGTK.glade, GUI binaries)
# and WebUI/plugson.www from build_gui_all.sh.
rm -rf "$PAYLOAD"/boot "$PAYLOAD"/config "$PAYLOAD"/hiperiso "$PAYLOAD"/EFI "$PAYLOAD"/grub
rm -f "$PAYLOAD"/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
mkdir -p "$PAYLOAD/boot"
mkdir -p "$PAYLOAD/config"
mkdir -p "$PAYLOAD/hiperiso"
mkdir -p "$PAYLOAD/EFI/BOOT"
mkdir -p "$PAYLOAD/EFI/hiperiso/trace"
mkdir -p "$PAYLOAD/grub"
mkdir -p "$PAYLOAD/tool/x86_64"
_progress 1 "Copying boot images & EFI payloads..."
# ── boot/ (BIOS boot images, vendored) ────────────────────────────
cp "$HIPERISO_ROOT/vendor/grub-i386-pc/boot.img" "$PAYLOAD/boot/boot.img"
cp "$HIPERISO_ROOT/vendor/grub-i386-pc/core.img" "$PAYLOAD/boot/core.img"
xz --check=crc32 "$PAYLOAD/boot/core.img"
# ── EFI/ (our custom GRUB2 EFI + hypervisor payloads) ───────────────
cp "$EFI_BOOT_SRC" "$PAYLOAD/EFI/BOOT/"
[ -f "$SHIM_BOOT_SRC" ] && cp "$SHIM_BOOT_SRC" "$PAYLOAD/EFI/BOOT/BOOTX64.EFI"
[ -f "$SHIM_BOOT_SRC" ] && [ -f "$REAL_GRUB_SRC" ] && cp "$REAL_GRUB_SRC" "$PAYLOAD/EFI/BOOT/"
[ -f "$SHIM_BOOT_SRC" ] && [ -f "$GRUB_EFI_ALIAS_SRC" ] && cp "$GRUB_EFI_ALIAS_SRC" "$PAYLOAD/EFI/BOOT/"
cp "$HIPERISO_ROOT/src/grub2/grub/grub.cfg" "$PAYLOAD/EFI/BOOT/"
[ -f "$SHIM_BOOT_SRC" ] && [ -f "$HIPERISO_ROOT/vendor/secureboot/mmx64.efi" ] && \
cp "$HIPERISO_ROOT/vendor/secureboot/mmx64.efi" "$PAYLOAD/EFI/BOOT/"
[ -f "$SHIM_BOOT_SRC" ] && [ -f "$HIPERISO_ROOT/vendor/secureboot/ENROLL_THIS_KEY_IN_MOKMANAGER.cer" ] && \
cp "$HIPERISO_ROOT/vendor/secureboot/ENROLL_THIS_KEY_IN_MOKMANAGER.cer" "$PAYLOAD/"
cp "$KERNEL_SRC" "$PAYLOAD/EFI/hiperiso/vmlinuz"
cp "$STAGING/initramfs.cpio.gz" "$PAYLOAD/EFI/hiperiso/"
cp "$STAGING/OVMF.fd" "$PAYLOAD/EFI/hiperiso/"
cp "$STAGING/hiperiso-log" "$PAYLOAD/EFI/hiperiso/"
cp "$HIPERISO_ROOT/logging/trace-"*.events "$PAYLOAD/EFI/hiperiso/trace/"
_progress 2 "Copying GRUB2 configs, themes & modules..."
# ── grub/ (configs, themes, modules from GRUB2 2.04 build) ──────────
cp "$HIPERISO_ROOT/src/grub2/grub/grub.cfg" "$PAYLOAD/grub/"
cp -a "$GRUB_X64_DIR" "$PAYLOAD/grub/x86_64-efi"
mkdir -p "$PAYLOAD/grub/i386-pc"
cp "$HIPERISO_ROOT/vendor/grub-i386-pc/"*.lst "$PAYLOAD/grub/i386-pc/" 2>/dev/null || true
cp "$HIPERISO_ROOT/vendor/grub-i386-pc/"*.mod "$PAYLOAD/grub/i386-pc/" 2>/dev/null || true
for cfg in checksum.cfg debug.cfg hwinfo.cfg keyboard.cfg localboot.cfg menulang.cfg power.cfg; do
cp "$HIPERISO_ROOT/src/grub2/grub/$cfg" "$PAYLOAD/grub/" 2>/dev/null || true
done
for dir in distro help menu themes fonts; do
cp -a "$HIPERISO_ROOT/src/grub2/grub/$dir" "$PAYLOAD/grub/" 2>/dev/null || true
done
if [ -d "$PAYLOAD/grub/help" ]; then
tar -C "$PAYLOAD/grub" -czf "$PAYLOAD/grub/help.tar.gz" help
fi
if [ -d "$PAYLOAD/grub/menu" ]; then
tar -C "$PAYLOAD/grub" -czf "$PAYLOAD/grub/menu.tar.gz" menu
fi
_progress 3 "Copying installer tools & scripts..."
# ── tool/ (installer scripts + vendored assets + binary tools) ─────
cp "$HIPERISO_ROOT/src/installer/tool/hiperiso_lib.sh" "$PAYLOAD/tool/"
cp "$HIPERISO_ROOT/src/installer/tool/HiperisoWorker.sh" "$PAYLOAD/tool/"
cp "$HIPERISO_ROOT/src/installer/tool/create_hiperiso_iso_part_dm.sh" "$PAYLOAD/tool/"
cp "$HIPERISO_ROOT/assets/languages.json" "$PAYLOAD/tool/languages.json"
cp "$HIPERISO_ROOT/assets/HiperisoGTK.glade" "$PAYLOAD/tool/HiperisoGTK.glade"
[ -f "$HIPERISO_ROOT/vendor/secureboot/ENROLL_THIS_KEY_IN_MOKMANAGER.cer" ] && \
cp "$HIPERISO_ROOT/vendor/secureboot/ENROLL_THIS_KEY_IN_MOKMANAGER.cer" "$PAYLOAD/tool/"
for tool in ash hexdump mkexfatfs mount.exfat-fuse xzcat; do
cp "$HIPERISO_ROOT/vendor/tool-x86_64/$tool" "$PAYLOAD/tool/x86_64/"
done
[ -f "$PAYLOAD/tool/x86_64/Hiperiso2Disk.qt5" ] && chmod +x "$PAYLOAD/tool/x86_64/Hiperiso2Disk.qt5"
[ -f "$PAYLOAD/tool/x86_64/Hiperiso2Disk.gtk3" ] && chmod +x "$PAYLOAD/tool/x86_64/Hiperiso2Disk.gtk3"
# ── Top-level scripts ───────────────────────────────────────────────
for f in Hiperiso.sh HiperisoQt.sh HiperisoGtk.sh HiperisoWeb.sh HiperisoPlugson.sh \
Hiperiso2Disk.sh CreatePersistentImg.sh ExtendPersistentImg.sh hisocli hisolnk; do
cp "$HIPERISO_ROOT/src/installer/$f" "$PAYLOAD/"
chmod +x "$PAYLOAD/$f"
done
# ── config/ ─────────────────────────────────────────────────────────
cp "$HIPERISO_ROOT/config/hiperiso.json.example" "$PAYLOAD/config/"
# ── version ─────────────────────────────────────────────────────────
echo "1.0.0" > "$PAYLOAD/hiperiso/version"
_progress 4 "Extracting support files..."
# Extract direct-boot support files
if [ -f "$HIPERISO_ROOT/vendor/support-x64.tar.xz" ]; then
tar -xJf "$HIPERISO_ROOT/vendor/support-x64.tar.xz" -C "$STAGING/"
cp -a "$STAGING/support-x64/"* "$PAYLOAD/hiperiso/"
fi
# Copy Ventoy's runtime modules into the payload. The modsrc's GRUB
# binary runs ventoy_check_official_device() at boot, which requires
# `ventoy/ventoy.cpio` on the ESP. We vendor it under
# `vendor/ventoy-runtime/` (sourced from upstream Ventoy 1.0.96, the
# same version our modsrc is built from). Without this, the modsrc's
# GRUB halts with "This is NOT a standard Ventoy device" before the
# menu ever renders.
mkdir -p "$PAYLOAD/hiperiso/ventoy"
if [ -f "$HIPERISO_ROOT/vendor/ventoy-runtime/ventoy.cpio" ]; then
cp "$HIPERISO_ROOT/vendor/ventoy-runtime/ventoy.cpio" \
"$PAYLOAD/hiperiso/ventoy/ventoy.cpio"
fi
rm -f "$PAYLOAD/log.txt"
_progress 5 "Staging ESP content tree..."
ESP_IMG="$PAYLOAD/hiperiso/hiperiso.disk.img"
ESP_STAGING=$(mktemp -d)
trap 'rm -rf "$ESP_STAGING"' EXIT INT TERM
mkdir -p "$ESP_STAGING/EFI/BOOT" "$ESP_STAGING/EFI/hiperiso/trace" \
"$ESP_STAGING/grub" "$ESP_STAGING/tool" "$ESP_STAGING/hiperiso"
cp "$PAYLOAD/EFI/BOOT/BOOTX64.EFI" "$PAYLOAD/EFI/BOOT/grub.cfg" "$ESP_STAGING/EFI/BOOT/"
[ -f "$PAYLOAD/EFI/BOOT/grubx64_real.efi" ] && cp "$PAYLOAD/EFI/BOOT/grubx64_real.efi" "$ESP_STAGING/EFI/BOOT/"
[ -f "$PAYLOAD/EFI/BOOT/grubx64.efi" ] && cp "$PAYLOAD/EFI/BOOT/grubx64.efi" "$ESP_STAGING/EFI/BOOT/"
[ -f "$PAYLOAD/EFI/BOOT/mmx64.efi" ] && cp "$PAYLOAD/EFI/BOOT/mmx64.efi" "$ESP_STAGING/EFI/BOOT/"
[ -f "$PAYLOAD/ENROLL_THIS_KEY_IN_MOKMANAGER.cer" ] && cp "$PAYLOAD/ENROLL_THIS_KEY_IN_MOKMANAGER.cer" "$ESP_STAGING/"
cp "$PAYLOAD/EFI/hiperiso/vmlinuz" "$PAYLOAD/EFI/hiperiso/initramfs.cpio.gz" \
"$PAYLOAD/EFI/hiperiso/OVMF.fd" "$PAYLOAD/EFI/hiperiso/hiperiso-log" "$ESP_STAGING/EFI/hiperiso/"
cp "$PAYLOAD"/EFI/hiperiso/trace/*.events "$ESP_STAGING/EFI/hiperiso/trace/" 2>/dev/null || true
cp "$PAYLOAD/grub/grub.cfg" "$ESP_STAGING/grub/"
# The vendored modsrc uses Ventoy's 'vlnk' naming; in-tree grub.cfg
# uses rebrand 'hlnk'. Rewrite the deployed config to match the binary.
if [ -f "$ESP_STAGING/grub/grub.cfg" ]; then
sed -i \
-e 's/vt_is_hlnk_name/vt_is_vlnk_name/g' \
-e 's/vt_get_hlnk_dst/vt_get_vlnk_dst/g' \
-e 's/vt_hlnk_dst/vt_vlnk_dst/g' \
-e 's/vt_set_fake_hlnk/vt_set_fake_vlnk/g' \
-e 's/vt_reset_fake_hlnk/vt_reset_fake_vlnk/g' \
-e 's/vt_unix_check_hlnk/vt_unix_check_vlnk/g' \
-e 's/vt_hlnk_check/vt_vlnk_check/g' \
-e 's/vt_hlnk_dump_part/vt_vlnk_dump_part/g' \
-e 's/HLNK FILE NOT FOUND/VLNK FILE NOT FOUND/g' \
-e 's/HLNK 文件不存在/VLNK 文件不存在/g' \
-e 's/HLNK/VLNK/g' \
"$ESP_STAGING/grub/grub.cfg"
fi
# Copy chain-boot EFI binaries + helpers to the ESP at /hiperiso/
# (grub.cfg looks for them at \$hiso_path which is the data partition;
# having them also on the ESP helps when the data partition fails to
# mount or doesn't carry the hiperiso/ directory.)
mkdir -p "$ESP_STAGING/hiperiso"
for efi in hiperiso_x64.efi iso9660_x64.efi udf_x64.efi vtoyutil_x64.efi wimboot.x86_64.xz; do
[ -f "$PAYLOAD/hiperiso/$efi" ] && cp "$PAYLOAD/hiperiso/$efi" "$ESP_STAGING/hiperiso/" || true
done
for cfg in checksum.cfg debug.cfg hwinfo.cfg keyboard.cfg localboot.cfg menulang.cfg power.cfg; do
[ -f "$PAYLOAD/grub/$cfg" ] && cp "$PAYLOAD/grub/$cfg" "$ESP_STAGING/grub/" || true
done
[ -f "$PAYLOAD/grub/help.tar.gz" ] && cp "$PAYLOAD/grub/help.tar.gz" "$ESP_STAGING/grub/"
[ -f "$PAYLOAD/grub/menu.tar.gz" ] && cp "$PAYLOAD/grub/menu.tar.gz" "$ESP_STAGING/grub/"
for dir in themes fonts distro help menu x86_64-efi i386-pc; do
[ -d "$PAYLOAD/grub/$dir" ] && cp -a "$PAYLOAD/grub/$dir" "$ESP_STAGING/grub/" || true
done
find "$ESP_STAGING/grub" -name '*.module' -delete 2>/dev/null || true
find "$ESP_STAGING/grub" -name '*.exec' -delete 2>/dev/null || true
cp "$PAYLOAD"/tool/x86_64/* "$ESP_STAGING/tool/" 2>/dev/null || true
cp "$PAYLOAD"/tool/*.sh "$PAYLOAD"/tool/*.json "$PAYLOAD"/tool/*.glade "$PAYLOAD"/tool/*.cer \
"$ESP_STAGING/tool/" 2>/dev/null || true
cp "$PAYLOAD/hiperiso/version" "$ESP_STAGING/hiperiso/"
for f in "$PAYLOAD"/hiperiso/*; do
[ -f "$f" ] || continue
case "$(basename "$f")" in hiperiso.disk.img*) continue ;; esac
cp "$f" "$ESP_STAGING/hiperiso/"
done
for d in 7z imdisk; do
[ -d "$PAYLOAD/hiperiso/$d" ] && cp -a "$PAYLOAD/hiperiso/$d" "$ESP_STAGING/hiperiso/" || true
done
# Stage ventoy/ at the ESP root. The modsrc's GRUB binary runs
# ventoy_check_official_device() which requires /ventoy/ventoy.cpio
# to be at the partition root (not under hiperiso/). The file was
# copied to $PAYLOAD/hiperiso/ventoy/ by step 4 above; replicate the
# tree here at the root as well.
if [ -d "$PAYLOAD/hiperiso/ventoy" ]; then
cp -a "$PAYLOAD/hiperiso/ventoy" "$ESP_STAGING/"
fi
_progress 6 "Creating 32MB FAT16 ESP image ($(find "$ESP_STAGING" -type f | wc -l) files, $(du -sh "$ESP_STAGING" | cut -f1))..."
dd if=/dev/zero of="$ESP_IMG" bs=1M count=32 2>/dev/null
# FAT16 volume label MUST be "VTOYEFI" (modsrc's GRUB hardcodes
# this check at ventoy_check_official_device). Using "HISOEFI" here
# would fail with error 10 "Partition name is not VTOYEFI".
mkfs.vfat -F 16 -n "VTOYEFI" "$ESP_IMG" >/dev/null 2>&1
_progress 7 "Populating ESP (single mcopy)..."
# mcopy with a wildcard of subdirs + ::/ does not recurse reliably
# in all mtools versions. Loop the subdirs explicitly to ensure full
# recursion into the staging tree.
for entry in "$ESP_STAGING"/*; do
name=$(basename "$entry")
if [ -d "$entry" ]; then
mcopy -s -i "$ESP_IMG" "$entry" "::/$name" 2>/dev/null || true
elif [ -f "$entry" ]; then
mcopy -i "$ESP_IMG" "$entry" "::/$name" 2>/dev/null || true
fi
done
rm -rf "$ESP_STAGING"
trap - EXIT INT TERM
_progress 8 "Compressing ESP image ($(du -h "$ESP_IMG" | cut -f1))..."
xz --check=crc32 "$ESP_IMG"
echo "=== hiperiso release package assembled ==="
du -sh "$PAYLOAD"
find "$PAYLOAD" -type f | wc -l
echo "files"