1
0
Signed-off-by: Stefan Knoblich <stkn@bitplumber.de>
This commit is contained in:
2026-06-03 22:13:08 +02:00
parent e577b48c6c
commit 09cb10af73
+246 -88
View File
@@ -201,86 +201,6 @@ function fileext_from_qemu_image_type {
esac esac
} }
function qemu_prepare_disk {
local QEMU_DISK_FILE="${1}"
local QEMU_DISK_SIZE="${2:-32G}"
# Remove leftover temp files
rm -f "${QEMU_DISK_FILE}.tmp" 2>/dev/null
if [[ ! -f "${QEMU_DISK_FILE}" || "${FORCE_RESET}" -eq 1 ]]; then
echo "Creating QEMU disk image..." >&2
qemu-img create -f qcow2 "${QEMU_DISK_FILE}" "${QEMU_DISK_SIZE}" >/dev/null || return $?
elif [[ -f "${QEMU_DISK_FILE}" ]]; then
local QEMU_COW_FILE="${QEMU_DISK_FILE}.cow"
local QEMU_COW_SIZE="$(qemu_image_size "${QEMU_DISK_FILE}")" || return $?
echo "Creating QEMU CoW disk image for '$(basename "${QEMU_DISK_FILE}")' ..." >&2
qemu-img create -f qcow2 -B qcow2 -b "${QEMU_DISK_FILE}" "${QEMU_COW_FILE}" "${QEMU_COW_SIZE}" >/dev/null || return $?
fi
#
QEMU_DYN_OPTIONS+=(
"-drive if=none,format=qcow2,file=${QEMU_COW_FILE:-${QEMU_DISK_FILE}},discard=unmap,id=hd0"
"-device virtio-blk-pci,drive=hd0,bootindex=1"
)
}
function qemu_prepare_cdrom_amd64 {
local QEMU_BOOTINDEX=2 # First non-HD drive bootindex
# Only assign cdrom drives for build command (TODO: clean this up)
[[ "${COMMAND}" == "build" ]] || return 0;
[[ -n "${UNATTEND_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${UNATTEND_ISO},media=cdrom,id=cd2"
"-device ide-cd,drive=cd2,bootindex=$(( QEMU_BOOTINDEX++ )),bus=ahci.2"
)
}
[[ -n "${INSTALL_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${INSTALL_ISO},media=cdrom,id=cd0"
"-device ide-cd,drive=cd0,bootindex=$(( QEMU_BOOTINDEX++ )),bus=ahci.0"
)
}
[[ -n "${VIRTIO_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${VIRTIO_ISO},media=cdrom,id=cd1"
"-device ide-cd,drive=cd1,bootindex=$(( QEMU_BOOTINDEX++ )),bus=ahci.1"
)
}
}
function qemu_prepare_cdrom_arm64 {
local QEMU_BOOTINDEX=2 # First non-HD drive bootindex
# Only assign cdrom drives for build command (TODO: clean this up)
[[ "${COMMAND}" == "build" ]] || return 0;
[[ -n "${UNATTEND_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${UNATTEND_ISO},media=cdrom,id=cd2"
"-device usb-storage,drive=cd2,bootindex=$(( QEMU_BOOTINDEX++ ))"
)
}
[[ -n "${INSTALL_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${INSTALL_ISO},media=cdrom,id=cd0"
"-device usb-storage,drive=cd0,bootindex=$(( QEMU_BOOTINDEX++ ))"
)
}
[[ -n "${VIRTIO_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${VIRTIO_ISO},media=cdrom,id=cd1"
"-device usb-storage,drive=cd1,bootindex=$(( QEMU_BOOTINDEX++ ))"
)
}
}
function expand_size { function expand_size {
local value="${1}" local value="${1}"
@@ -302,25 +222,263 @@ function expand_size {
esac esac
} }
function resize_image { function do_resize_image {
local img_file="${1}" local img_file="${1}"
local img_type="${2}"
local img_cur_size="${3}"
local img_req_size="${4}"
local img_cur_size="$(qemu_image_size "${1}")" [[ "${img_cur_size}" -eq "${img_req_size}" ]] && return 0
local img_req_size="$(expand_size "${2:-${img_cur_size}}")" [[ "${img_cur_size}" -gt "${img_req_size}" ]] && {
[[ "${img_cur_size}" -eq "${img_req_size}" ]] && return 0; echo "Shrinking ${img_type} images is not supported" >&2
[[ "${img_cur_size}" -lt "${img_req_size}" ]] || return 1; return 1
}
local img_type="$(qemu_image_type_from_fileext "${img_file}")"
case "${img_type}" in case "${img_type}" in
raw) "raw")
echo "Resizing raw image '$(basename "${img_file}")'" >&2 echo "Resizing raw image '$(basename "${img_file}")'" >&2
truncate --size="${img_req_size}" "${img_file}" || return $? ;; truncate --size="${img_req_size}" "${img_file}" || return $? ;;
"qcow2")
echo "Resizing qcow2 image '$(basename "${img_file}")'" >&2
qemu-img resize -f qcow2 "${img_file}" "${img_req_size}" || return $? ;;
*) *)
echo "Qcow2 image resizing is currently not implemented" >&2 echo "Resizing ${img_type} images is currently not supported" >&2
return 1 ;; return 1 ;;
esac esac
} }
function resize_image {
local img_file="${1}"
local img_type="$(qemu_image_type_from_fileext "${img_file}")"
local img_cur_size="$(qemu_image_size "${1}")"
local img_req_size="$(expand_size "${2:-${img_cur_size}}")"
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"
"vioscsi"
"viostor"
"viogpudo"
)
function has {
local val="${1}"; shift
for x in $@; do
[[ "${x}" == "${val}" ]] && return 0
done
return 1
}
#
#
#
function qemu_fill_unattend_fs {
local destdir="${1}"
[[ -d "${destdir}" ]] || {
echo "ERROR: Virtual VFAT target directory '${destdir}' does not exist" >&2
return 1
}
local unattend_xml="${2}"
[[ -f "${unattend_xml}" ]] || {
echo "ERROR: Unattended XML installation file '${unattend_xml}' does not exist" >&2
return 1
}
# Copy autounattend.xml
sed -e "s|processorArchitecture=\"[^\"]\+\"|processorArchitecture=\"${GUEST_ARCH}\"|g" \
< "${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
# Copy virtio drivers
local virtio_iso="${3}"
[[ -f "${virtio_iso}" ]] || {
echo "ERROR: VirtIO ISO image '${virtio_iso}' does not exist" >&2
return 1
}
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
return 1
}
echo "Copying virtio drivers '${virtio_drivers_list//$'\n'/,}' into unattend VFS..." >&2
mkdir -p "${destdir}/drivers" "${destdir}/\$WinPEDriver\$" || return $?
for x in ${virtio_drivers_list}; do
mkdir -p "${destdir}/drivers/${x}" || return $?
7z e -y -bd -bb0 -o"${destdir}/drivers/${x}" -- "${virtio_iso}" "${x}/w11/${virtio_arch}/*" >/dev/null || return $?
has "${x}" "${VIRTIO_WINPE_DRIVERS[@]}" && {
echo "Copying ${x} into \$WinPEDriver\$..." >&2
find "${destdir}/drivers/${x}/" -maxdepth 1 -type f -exec cp '{}' "${destdir}/\$WinPEDriver\$/" \; || return $?
}
done
}
function qemu_generate_unattend_iso {
local destfile="${1}"
local destdir="${BASEDIR}/unattend.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
# cleanup
find "${destdir}" -delete || return $?
}
function qemu_prepare_disk {
local QEMU_DISK_FILE="${1}"
local QEMU_DISK_SIZE="${2:-32G}"
# Remove leftover temp files
rm -f "${QEMU_DISK_FILE}.tmp" 2>/dev/null
if [[ ! -f "${QEMU_DISK_FILE}" || "${FORCE_RESET}" -eq 1 ]]; then
echo "Creating QEMU disk image..." >&2
qemu-img create -f qcow2 "${QEMU_DISK_FILE}" "${QEMU_DISK_SIZE}" >/dev/null || return $?
elif [[ -f "${QEMU_DISK_FILE}" && "${COMMAND}" != "build" ]]; then
local QEMU_COW_FILE="${QEMU_DISK_FILE}.cow"
local QEMU_COW_SIZE="$(qemu_image_size "${QEMU_DISK_FILE}")" || return $?
echo "Creating QEMU CoW disk image for '$(basename "${QEMU_DISK_FILE}")' ..." >&2
qemu-img create -f qcow2 -B qcow2 -b "${QEMU_DISK_FILE}" "${QEMU_COW_FILE}" "${QEMU_COW_SIZE}" >/dev/null || return $?
fi
QEMU_DYN_OPTIONS+=(
"-drive if=none,format=qcow2,file=${QEMU_COW_FILE:-${QEMU_DISK_FILE}},discard=unmap,id=hd0,index=0"
"-device virtio-blk-pci,drive=hd0,bootindex=1"
)
}
function qemu_prepare_cdrom_amd64 {
local QEMU_BOOTINDEX=2 # First non-HD drive bootindex
local QEMU_DRIVEINDEX=1 # First non-HD drive index
# Only assign cdrom drives for build command (TODO: clean this up)
[[ "${COMMAND}" == "build" ]] || return 0;
if [[ -n "${UNATTEND_CONFIG}" ]]; then
local unattend_iso="${BASEDIR}/unattend.iso"
qemu_generate_unattend_iso "${unattend_iso}" "${UNATTEND_CONFIG}" "${VIRTIO_ISO}" || return $?
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${unattend_iso},media=cdrom,id=cd2,index=$(( QEMU_DRIVEINDEX++ ))"
"-device ide-cd,drive=cd2,bootindex=$(( QEMU_BOOTINDEX++ )),bus=ahci.2"
)
#local unattend_tmp="${BASEDIR}/unattend"
#mkdir -p "${unattend_tmp}" || return $?
#qemu_fill_unattend_fs "${unattend_tmp}" "${UNATTEND_CONFIG}" "${VIRTIO_ISO}" || return $?
#QEMU_DYN_OPTIONS+=(
# "-drive if=none,file=fat:rw:${unattend_tmp},format=raw,id=cd2,index=$(( QEMU_DRIVEINDEX++ ))"
# "-device usb-storage,drive=cd2,bootindex=$(( QEMU_BOOTINDEX++ )),removable=on"
#)
elif [[ -n "${UNATTEND_ISO}" ]]; then
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${UNATTEND_ISO},media=cdrom,id=cd2,index=$(( QEMU_DRIVEINDEX++ ))"
"-device ide-cd,drive=cd2,bootindex=$(( QEMU_BOOTINDEX++ )),bus=ahci.2"
)
fi
[[ -n "${INSTALL_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${INSTALL_ISO},media=cdrom,id=cd0,index=$(( QEMU_DRIVEINDEX++ ))"
"-device ide-cd,drive=cd0,bootindex=$(( QEMU_BOOTINDEX++ )),bus=ahci.0"
)
}
[[ -n "${VIRTIO_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${VIRTIO_ISO},media=cdrom,id=cd1,index=$(( QEMU_DRIVEINDEX++ ))"
"-device ide-cd,drive=cd1,bootindex=$(( QEMU_BOOTINDEX++ )),bus=ahci.1"
)
}
}
function qemu_prepare_cdrom_arm64 {
local QEMU_BOOTINDEX=2 # First non-HD drive bootindex
local QEMU_DRIVEINDEX=1 # First non-HD drive index
# Only assign cdrom drives for build command (TODO: clean this up)
[[ "${COMMAND}" == "build" ]] || return 0;
if [[ -n "${UNATTEND_CONFIG}" ]]; then
local unattend_iso="${BASEDIR}/unattend.iso"
qemu_generate_unattend_iso "${unattend_iso}" "${UNATTEND_CONFIG}" "${VIRTIO_ISO}" || return $?
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${unattend_iso},media=cdrom,id=cd2,index=$(( QEMU_DRIVEINDEX++ ))"
"-device usb-storage,drive=cd2,bootindex=$(( QEMU_BOOTINDEX++ ))"
)
# Using Qemu's VVFAT support to create an unattend drive (NOK: blocks C: / Disk #0)
#local unattend_tmp="${BASEDIR}/unattend"
#mkdir -p "${unattend_tmp}" || return $?
#qemu_fill_unattend_fs "${unattend_tmp}" "${UNATTEND_CONFIG}" "${VIRTIO_ISO}" || return $?
#QEMU_DYN_OPTIONS+=(
# "-drive if=none,file=fat:${unattend_tmp},media=disk,format=raw,id=cd2,index=$(( QEMU_DRIVEINDEX++ ))"
# "-device usb-storage,drive=cd2,bootindex=$(( QEMU_BOOTINDEX++ )),removable=on"
#)
elif [[ -n "${UNATTEND_ISO}" ]]; then
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${UNATTEND_ISO},media=cdrom,id=cd2,index=$(( QEMU_DRIVEINDEX++ ))"
"-device usb-storage,drive=cd2,bootindex=$(( QEMU_BOOTINDEX++ ))"
)
fi
[[ -n "${INSTALL_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${INSTALL_ISO},media=cdrom,id=cd0,index=$(( QEMU_DRIVEINDEX++ ))"
"-device usb-storage,drive=cd0,bootindex=$(( QEMU_BOOTINDEX++ ))"
)
}
[[ -n "${VIRTIO_ISO}" ]] && {
QEMU_DYN_OPTIONS+=(
"-drive if=none,file=${VIRTIO_ISO},media=cdrom,id=cd1,index=$(( QEMU_DRIVEINDEX++ ))"
"-device usb-storage,drive=cd1,bootindex=$(( QEMU_BOOTINDEX++ ))"
)
}
}
function qemu_prepare_efi_code_and_vars { function qemu_prepare_efi_code_and_vars {
local SRC_EFI_CODE_IMG="${1}" # Required: EFI code image path local SRC_EFI_CODE_IMG="${1}" # Required: EFI code image path
local SRC_EFI_VARS_IMG="${2}" # Optional: EFI vars image path local SRC_EFI_VARS_IMG="${2}" # Optional: EFI vars image path