Signed-off-by: Stefan Knoblich <stkn@bitplumber.de>
This commit is contained in:
2026-08-06 13:20:22 +02:00
parent b09d3b16e2
commit 6d1873e635
3 changed files with 69 additions and 49 deletions
+64 -48
View File
@@ -1,26 +1,30 @@
#!/usr/bin/env /bin/bash
declare -r TOP_BASEDIR="`pwd`"
declare -r TOP_BASEDIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)"
# read global builder config
[[ -f "${TOP_BASEDIR}/builder.config" ]] && {
source "${TOP_BASEDIR}/builder.config" || exit $?
}
#
# ISO images
#
declare -r ISO_BASEDIR="/mnt/machines/iso"
# Windows installation ISO
#declare -r INSTALL_ISO="${ISO_BASEDIR}/Win11_25H2_English_x64_v2.iso"
#declare -r INSTALL_ISO="${ISO_BASEDIR}/nano11-25H2-English-Pro-2026-03-20.iso"
declare -r INSTALL_ISO="${TOP_BASEDIR}/output/install-builder-amd64-20260601.iso"
declare -r INSTALL_ISO="${ISO_BASEDIR}/nano11-base-25H2-Pro-Eng-amd64-20260526.iso"
#declare -r INSTALL_ISO="${TOP_BASEDIR}/output/install-builder-amd64-20260601.iso"
# Unattended installation add-on ISO
#declare -r UNATTEND_ISO="${TOP_BASEDIR}/output/unattend.iso"
declare -r UNATTEND_CONFIG="${TOP_BASEDIR}/configs/autounattend-builder-amd64-20260604.xml"
declare -r VIRTIO_ISO="${ISO_BASEDIR}/virtio-win-0.1.285.iso"
#
# Disk images
#
declare -r DISK_BASEDIR="/mnt/machines/qemu-machines"
#declare -r DISK_IMG="${DISK_BASEDIR}/win11-builder-amd64.qcow2"
declare -r DISK_IMG="${DISK_BASEDIR}/win11-builder-amd64.qcow2"
declare -r DISK_SIZE="32G"
#
@@ -67,11 +71,21 @@ declare -r ARM64_EFI_CODE_SIZE="64M"
declare -r COMMAND="${1:-build}"
shift
function has {
local val="${1}"
shift
for x in $@; do
[[ "${x}" == "${val}" ]] && return 0
done
return 1
}
function detect_iso_arch {
local iso_file="${1}"
local fallback_arch="${2}"
case "${iso_file@L}" in
*-amd64-*|*-x64-*)
*-amd64-*|*-x64-*|*_x64_*)
echo "amd64" ;;
*-arm64-*|*-aarch64-*)
echo "arm64" ;;
@@ -92,14 +106,14 @@ function detect_host_arch {
# Detect host and guest architecture
declare -r HOST_ARCH="$(detect_host_arch)"
[[ -n "${HOST_ARCH}" ]] || {
echo "Failed to detect host arch" >&2;
exit 1;
echo "Failed to detect host arch" >&2
exit 1
}
declare -r GUEST_ARCH="$(detect_iso_arch "${INSTALL_ISO}" "${HOST_ARCH}")"
[[ -n "${GUEST_ARCH}" ]] || {
echo "Failed to detect guest arch" >&2;
exit 1;
echo "Failed to detect guest arch" >&2
exit 1
}
# Setup locations
@@ -201,7 +215,6 @@ function fileext_from_qemu_image_type {
esac
}
function expand_size {
local value="${1}"
[[ "${value}" =~ ^[0-9]+$ ]] && {
@@ -256,7 +269,6 @@ function resize_image {
do_resize_image "${img_file}" "${img_type}" "${img_cur_size}" "${img_req_size}"
}
# Drivers for the WinPE early installation environment
declare -r VIRTIO_WINPE_DRIVERS=(
"NetKVM"
@@ -265,12 +277,15 @@ declare -r VIRTIO_WINPE_DRIVERS=(
"viogpudo"
)
function has {
local val="${1}"; shift
for x in $@; do
[[ "${x}" == "${val}" ]] && return 0
done
return 1
function guest_to_virtio_arch {
local arch="${1@L}"
case "${arch}" in
"arm64") echo "${arch@U}" ;;
"amd64") echo "${arch}" ;;
*)
echo "ERROR: Failed to determine virtio arch from '${arch}'" >&2
return 1 ;;
esac
}
#
@@ -294,16 +309,11 @@ function qemu_fill_unattend_fs {
< "${unattend_xml}" > "${destdir}/autounattend.xml" || return $?
#
local virtio_arch="${GUEST_ARCH@L}"
case "${GUEST_ARCH@L}" in
"arm64")
virtio_arch="${GUEST_ARCH@U}" ;;
"amd64")
virtio_arch="${GUEST_ARCH@L}" ;;
*)
echo "ERROR: " >&2
return 1 ;;
esac
# Additional resources
# $OEM$\$$ -> C:\Windows
# $OEM$\$1 -> C:\
#
mkdir -p "${destdir}/\$OEM\$/\$\$" "${destdir}/\$OEM\$/\$1" || return $?
# Copy virtio drivers
local virtio_iso="${3}"
@@ -312,6 +322,7 @@ function qemu_fill_unattend_fs {
return 1
}
local virtio_arch="$(guest_to_virtio_arch "${GUEST_ARCH}")" || return $?
local virtio_drivers_list="$(7z l -slt "${virtio_iso}" | sed -ne "/^Path = [^/]\+\/w11\/${virtio_arch}\$/{ s|^Path = \([^/]\+\)/.*|\1|; p }")"
[[ -n "${virtio_drivers_list}" ]] || {
echo "ERROR: No drivers found in VirtIO ISO image '${virtio_iso}'" >&2
@@ -339,31 +350,36 @@ function qemu_fill_unattend_fs {
function qemu_generate_unattend_iso {
local destfile="${1}"
local destdir="${BASEDIR}/unattend.tmp"
local isogen_path=""
for x in "mkisofs" "genisoimage" "xorriso"; do
isogen_path="$(type -p "${x}" 2>/dev/null)" && break
done
[[ -n "${isogen_path}" ]] || {
echo "ERROR: Failed to find one of mkisofs | genisoimage | xorriso" >&2
return 1
}
local destdir="${BASEDIR}/unattend.${SRANDOM:-"tmp"}"
mkdir -p "${destdir}" || return $?
qemu_fill_unattend_fs "${destdir}" "${2}" "${3}" || return $?
if type -p "mkisofs" &>/dev/null; then
mkisofs \
-iso-level 3 -J -l -D -N -U -joliet-long -relaxed-filenames -rational-rock \
-V "win11-builder-unattend" -o "${destfile}" -quiet \
"${destdir}" || return $?
elif type -p "genisoimage" &>/dev/null; then
genisoimage \
-iso-level 3 -J -l -D -N -U -joliet-long -allow-limited-size -relaxed-filenames -rock \
-V "win11-builder-unattend" -o "${destfile}" -quiet \
"${destdir}" || return $?
elif type -p "xorriso" &>/dev/null; then
echo "ERROR: xorriso support is pending" >&2
return 1
else
echo "ERROR: Failed to find one of mkisofs | genisofs | xorriso" >&2
return 1
fi
local isogen_name="$(basename "${isogen_path}")"
case "${isogen_name}" in
"mkisofs")
${isogen_path} -iso-level 3 -J -l -D -N -U -joliet-long -relaxed-filenames -rational-rock \
-V "win11-builder-unattend" -o "${destfile}" -quiet "${destdir}" || return $? ;;
"genisoimage")
${isogen_path} -iso-level 3 -J -l -D -N -U -joliet-long -relaxed-filenames -rock -allow-limited-size \
-V "win11-builder-unattend" -o "${destfile}" -quiet "${destdir}" || return $? ;;
"xorriso")
echo "ERROR: ${isogen_name} support is pending" >&2
return 1 ;;
esac
# cleanup
find "${destdir}" -delete || return $?
find "${destdir}" -delete 2>/dev/null
return 0
}
function qemu_prepare_disk {