DistroHopper/quickemu
Martin Wimpress c94b6a0a56
Add support for boot and driver ISO image
Installing Windows 10 in VirtIO enabled Qemu requires additional drivers. This change makes it possible to exposed those drivers during a Windows 10 install.
2020-03-21 00:11:04 +00:00

365 lines
No EOL
9.9 KiB
Bash
Executable file

#!/usr/bin/env bash
function disk_delete() {
if [ -e "${disk_img}" ]; then
rm "${disk_img}"
echo "SUCCESS! Deleted ${disk_img}"
else
echo "NOTE! ${disk_img} not found. Doing nothing."
fi
}
function snapshot_apply() {
local snapshot_tag="${1}"
if [ -z "${snapshot_tag}" ]; then
echo "ERROR! No snapshot tag provided."
exit
fi
if [ -e "${disk_img}" ]; then
${QEMU_IMG} snapshot -q -a "${snapshot_tag}" "${disk_img}"
if [ $? -eq 0 ]; then
echo "SUCCESS! Applied snapshot ${snapshot_tag} to ${disk_img}"
else
echo "ERROR! Failed to apply snapshot ${snapshot_id} to ${disk_img}"
fi
else
echo "NOTE! ${disk_img} not found. Doing nothing."
fi
}
function snapshot_create() {
local snapshot_tag="${1}"
if [ -z "${snapshot_tag}" ]; then
echo "ERROR! No snapshot tag provided."
exit
fi
if [ -e "${disk_img}" ]; then
${QEMU_IMG} snapshot -q -c "${snapshot_tag}" "${disk_img}"
if [ $? -eq 0 ]; then
echo "SUCCESS! Created snapshot ${snapshot_tag} of ${disk_img}"
else
echo "ERROR! Failed to create snapshot ${snapshot_tag} of ${disk_img}"
fi
else
echo "NOTE! ${disk_img} not found. Doing nothing."
fi
}
function snapshot_delete() {
local snapshot_tag="${1}"
if [ -z "${snapshot_tag}" ]; then
echo "ERROR! No snapshot tag provided."
exit
fi
if [ -e "${disk_img}" ]; then
${QEMU_IMG} snapshot -q -d "${snapshot_tag}" "${disk_img}"
if [ $? -eq 0 ]; then
echo "SUCCESS! Deleted snapshot ${snapshot_tag} of ${disk_img}"
else
echo "ERROR! Failed to delete snapshot ${snapshot_tag} of ${disk_img}"
fi
else
echo "NOTE! ${disk_img} not found. Doing nothing."
fi
}
function snapshot_info() {
if [ -e "${disk_img}" ]; then
${QEMU_IMG} info "${disk_img}"
fi
}
function get_port() {
local PORT_START=22220
local PORT_RANGE=9
while true; do
local CANDIDATE=$[${PORT_START} + (${RANDOM} % ${PORT_RANGE})]
(echo "" >/dev/tcp/127.0.0.1/${CANDIDATE}) >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "${CANDIDATE}"
break
fi
done
}
function vm_boot() {
local VMNAME=$(basename ${VM} .conf)
local VMDIR=$(dirname ${disk_img})
local BIOS=""
local GL="on"
local VIRGL="on"
local UI="sdl"
local QEMU_VER=$(${QEMU} -version | head -n1 | cut -d' ' -f4 | cut -d'(' -f1)
echo "Starting ${VM}"
echo " - QEMU: ${QEMU} v${QEMU_VER}"
readonly disk_min_size=$((197632 * 8))
if [ -z "${disk}" ]; then
disk="64G"
fi
if [ ${ENABLE_EFI} -eq 1 ]; then
if [ -e /snap/qemu-virgil/current/usr/share/qemu/edk2-x86_64-code.fd ] ; then
if [ ! -e ${VMDIR}/${VMNAME}-vars.fd ]; then
cp /snap/qemu-virgil/current/usr/share/qemu/edk2-i386-vars.fd ${VMDIR}/${VMNAME}-vars.fd
fi
BIOS="-drive if=pflash,format=raw,readonly,file=/snap/qemu-virgil/current/usr/share/qemu/edk2-x86_64-code.fd -drive if=pflash,format=raw,file=${VMDIR}/${VMNAME}-vars.fd"
else
echo " - EFI: Booting requested but no EFI firmware found."
echo " Booting from Legacy BIOS."
fi
echo " - BIOS: EFI"
else
echo " - BIOS: Legacy"
fi
echo " - Disk: ${disk_img} (${disk})"
if [ ! -f "${disk_img}" ]; then
# If there is no disk image, create a new image.
${QEMU_IMG} create -q -f qcow2 "${disk_img}" "${disk}"
echo " Just created, booting from ${iso}"
if [ $? -ne 0 ]; then
echo "ERROR! Failed to create ${disk_img} of ${disk}. Stopping here."
exit 1
fi
elif [ -e ${disk_img} ]; then
# Check there isn't already a process attached to the disk image.
QEMU_LOCK_TEST=$(${QEMU_IMG} info ${disk_img} 2>/dev/null)
if [ $? -ne 0 ]; then
echo " Failed to get "write" lock. Is another process using the disk?"
exit 1
else
disk_curr_size=$(stat -c%s "${disk_img}")
if [ ${disk_curr_size} -le ${disk_min_size} ]; then
echo " Looks unused, booting from ${iso}"
else
# If there is a disk image, that appears to have an install
# then do not boot from the iso
iso=""
fi
fi
fi
# Has the status quo been requested?
if [ "${STATUSQUO}" == "-snapshot" ] && [ -z "${iso}" ]; then
echo " Existing disk state will be preserved, no writes will be committed."
fi
if [ -n "${iso}" ] && [ -e "${iso}" ]; then
local ISO_BOOT="-drive media=cdrom,file="${iso}",index=2"
echo " - Boot: ${iso}"
fi
if [ -n "${driver_iso}" ] && [ -e "${driver_iso}" ]; then
local ISO_DRIVER="-drive media=cdrom,file="${driver_iso}",index=3"
echo " - Drivers: ${driver_iso}"
fi
local cores="1"
local allcores=$(nproc --all)
if [ ${allcores} -ge 8 ]; then
cores="4"
elif [ ${allcores} -ge 4 ]; then
cores="2"
fi
echo " - CPU: ${cores} Core(s)"
local ram="2G"
local allram=$(free --mega -h | grep Mem | cut -d':' -f2 | cut -d'G' -f1 | sed 's/ //g')
if [ ${allram} -ge 64 ]; then
ram="4G"
elif [ ${allram} -ge 16 ]; then
ram="3G"
fi
echo " - RAM: ${ram}"
local xres=1152
local yres=648
if [ "${XDG_SESSION_TYPE}" == "x11" ]; then
local LOWEST_WIDTH=$(xrandr --listmonitors | grep -v Monitors | cut -d' ' -f4 | cut -d'/' -f1 | sort | head -n1)
if [ ${LOWEST_WIDTH} -ge 3840 ]; then
xres=3200
yres=1800
elif [ ${LOWEST_WIDTH} -ge 2560 ]; then
xres=2048
yres=1152
elif [ ${LOWEST_WIDTH} -ge 1920 ]; then
xres=1664
yres=936
elif [ ${LOWEST_WIDTH} -ge 1280 ]; then
xres=1152
yres=648
fi
fi
# GL is not working with GTK currently
if [ "${UI}" == "gtk" ]; then
GL="off"
else
echo " - Display: ${xres}x${yres}"
fi
echo " - GL: ${GL}"
echo " - Virgil3D: ${VIRGL}"
echo " - Output: ${UI^^}"
# Set the hostname of the VM
local NET="user,hostname=${VMNAME}"
# If smbd is available, export $HOME to the guest via samba
if [ -e /snap/qemu-virgil/current/usr/sbin/smbd ]; then
NET="${NET},smb=${HOME}"
fi
if [[ ${NET} == *"smb"* ]]; then
echo " - smbd: ${HOME} will be exported to the guest via smb://10.0.2.4/qemu"
else
echo " - smbd: ${HOME} will not be exported to the guest. 'smbd' not found."
fi
# Find a free port to expose ssh to the guest
local PORT=$(get_port)
if [ -n "${PORT}" ]; then
NET="${NET},hostfwd=tcp::${PORT}-:22"
echo " - ssh: ${PORT}/tcp is connected. Login via 'ssh user@localhost -p ${PORT}'"
else
echo " - ssh: All ports for exposing ssh have been exhausted."
fi
# Boot the iso image
${QEMU} -name ${VMNAME},process=${VMNAME} \
${BIOS} \
-drive id=disk,file=${disk_img},format=qcow2,if=virtio,aio=native,cache.direct=on \
${ISO_BOOT} ${ISO_DRIVER} \
-enable-kvm \
-machine q35,accel=kvm \
-cpu host,kvm=on \
-m ${ram} \
-smp ${cores} \
-netdev ${NET},id=nic \
-device virtio-net,netdev=nic \
-rtc base=localtime,clock=host \
-serial mon:stdio \
-audiodev pa,id=pa,server=unix:$XDG_RUNTIME_DIR/pulse/native,out.stream-name=${LAUNCHER}-${VMNAME},in.stream-name=${LAUNCHER}-${VMNAME} \
-device intel-hda -device hda-duplex,audiodev=pa \
-device qemu-xhci,id=xhci,p2=8,p3=8 -device usb-kbd -device usb-tablet \
-object rng-random,id=rng0,filename=/dev/urandom \
-device virtio-rng-pci,rng=rng0 \
-device virtio-vga,virgl=${VIRGL},xres=${xres},yres=${yres} \
-display ${UI},gl=${GL} ${STATUSQUO} \
"$@"
}
function usage() {
echo
echo "Usage"
echo " ${LAUNCHER} --vm ubuntu.conf"
echo
echo "You can also pass optional parameters"
echo " --delete : Delete the disk image."
echo " --efi : Enable EFI BIOS."
echo " --snapshot apply <tag> : Apply/restore a snapshot."
echo " --snapshot create <tag> : Create a snapshot."
echo " --snapshot delete <tag> : Delete a snapshot."
echo " --snapshot info : Show disk/snapshot info."
echo " --status-quo : Do not commit any changes to disk/snapshot."
exit 1
}
DELETE=0
ENABLE_EFI=0
readonly QEMU="/snap/bin/qemu-virgil"
readonly QEMU_IMG="/snap/bin/qemu-virgil.qemu-img"
readonly LAUNCHER=$(basename $0)
SNAPSHOT_ACTION=""
SNAPSHOT_TAG=""
STATUSQUO=""
VM=""
while [ $# -gt 0 ]; do
case "${1}" in
-efi|--efi)
ENABLE_EFI=1
shift;;
-delete|--delete)
DELETE=1
shift;;
-snapshot|--snapshot)
SNAPSHOT_ACTION="${2}"
if [ -z "${SNAPSHOT_ACTION}" ]; then
echo "ERROR! No snapshot action provided."
exit 1
fi
shift
SNAPSHOT_TAG="${2}"
if [ -z "${SNAPSHOT_TAG}" ] && [ "${SNAPSHOT_ACTION}" != "info" ]; then
echo "ERROR! No snapshot tag provided."
exit 1
fi
shift
shift;;
-status-quo|--status-quo)
STATUSQUO="-snapshot"
shift;;
-vm|--vm)
VM="$2"
shift
shift;;
-h|--h|-help|--help)
usage;;
*)
echo "ERROR! \"${1}\" is not a supported parameter."
usage;;
esac
done
# Check we have qemu-virgil available
if [ ! -e "${QEMU}" ] && [ ! -e "${QEMU_IMG}" ]; then
echo "ERROR! qemu-virgil not found. Please install the qemu-virgil snap."
echo " https://snapcraft.io/qemu-virgil"
exit 1
fi
if [ -n "${VM}" ] || [ -e "${VM}" ]; then
source "${VM}"
if [ -z "${disk_img}" ]; then
echo "ERROR! No disk_img defined."
exit 1
fi
else
echo "ERROR! Virtual machine configuration not found."
usage
fi
if [ ${DELETE} -eq 1 ]; then
disk_delete
exit
fi
if [ -n "${SNAPSHOT_ACTION}" ]; then
case ${SNAPSHOT_ACTION} in
apply)
snapshot_apply "${SNAPSHOT_TAG}"
snapshot_info
exit;;
create)
snapshot_create "${SNAPSHOT_TAG}"
snapshot_info
exit;;
delete)
snapshot_delete "${SNAPSHOT_TAG}"
snapshot_info
exit;;
info)
snapshot_info
exit;;
*)
echo "ERROR! \"${SNAPSHOT_ACTION}\" is not a supported snapshot action."
usage;;
esac
fi
vm_boot