+246
-88
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user