2020-03-15 23:13:25 +00:00
|
|
|
#!/usr/bin/env bash
|
2020-03-21 00:23:11 +00:00
|
|
|
export LC_ALL=C
|
2020-03-15 23:13:25 +00:00
|
|
|
|
2020-04-04 11:54:30 +00:00
|
|
|
function web_get() {
|
|
|
|
local URL="${1}"
|
2021-09-07 11:35:33 +00:00
|
|
|
local FILE=""
|
|
|
|
FILE="${URL##*/}"
|
2020-04-04 11:54:30 +00:00
|
|
|
if [ ! -e "${VMDIR}/${FILE}" ]; then
|
2021-09-07 11:35:33 +00:00
|
|
|
if ! wget -q -c "${URL}" -O "${VMDIR}/${FILE}"; then
|
2020-04-04 11:54:30 +00:00
|
|
|
echo "ERROR! Failed to download ${URL}"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2020-03-20 15:34:18 +00:00
|
|
|
function disk_delete() {
|
2020-03-20 18:12:13 +00:00
|
|
|
if [ -e "${disk_img}" ]; then
|
2020-03-15 23:13:25 +00:00
|
|
|
rm "${disk_img}"
|
2020-03-19 03:07:52 +00:00
|
|
|
echo "SUCCESS! Deleted ${disk_img}"
|
2020-03-20 18:12:13 +00:00
|
|
|
else
|
|
|
|
echo "NOTE! ${disk_img} not found. Doing nothing."
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
2021-09-07 11:35:33 +00:00
|
|
|
local VMNAME=""
|
|
|
|
VMNAME=$(basename "${VM}" .conf)
|
2020-04-02 22:23:12 +00:00
|
|
|
local SHORTCUT_DIR="/home/${USER}/.local/share/applications/"
|
2021-09-06 14:29:37 +00:00
|
|
|
if [ -e "${SHORTCUT_DIR}/${VMNAME}.desktop" ]; then
|
2020-04-02 22:23:12 +00:00
|
|
|
rm -v "${SHORTCUT_DIR}/${VMNAME}.desktop"
|
2021-09-06 21:27:06 +00:00
|
|
|
echo "Deleted ${VM} desktop shortcut"
|
2020-04-02 22:23:12 +00:00
|
|
|
fi
|
2020-03-15 23:13:25 +00:00
|
|
|
}
|
|
|
|
|
2020-03-20 18:17:53 +00:00
|
|
|
function snapshot_apply() {
|
2020-03-21 10:39:09 +00:00
|
|
|
local TAG="${1}"
|
|
|
|
if [ -z "${TAG}" ]; then
|
2020-03-20 18:17:53 +00:00
|
|
|
echo "ERROR! No snapshot tag provided."
|
|
|
|
exit
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -e "${disk_img}" ]; then
|
2021-09-07 11:35:33 +00:00
|
|
|
if ${QEMU_IMG} snapshot -q -a "${TAG}" "${disk_img}"; then
|
2020-03-21 10:39:09 +00:00
|
|
|
echo "SUCCESS! Applied snapshot ${TAG} to ${disk_img}"
|
2020-03-20 18:17:53 +00:00
|
|
|
else
|
2020-03-21 10:39:09 +00:00
|
|
|
echo "ERROR! Failed to apply snapshot ${TAG} to ${disk_img}"
|
2020-03-20 18:17:53 +00:00
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo "NOTE! ${disk_img} not found. Doing nothing."
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2020-03-20 18:17:53 +00:00
|
|
|
function snapshot_create() {
|
2020-03-21 10:39:09 +00:00
|
|
|
local TAG="${1}"
|
|
|
|
if [ -z "${TAG}" ]; then
|
2020-03-20 18:17:53 +00:00
|
|
|
echo "ERROR! No snapshot tag provided."
|
|
|
|
exit
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
2020-03-20 18:17:53 +00:00
|
|
|
|
|
|
|
if [ -e "${disk_img}" ]; then
|
2021-09-07 11:35:33 +00:00
|
|
|
if ${QEMU_IMG} snapshot -q -c "${TAG}" "${disk_img}"; then
|
2020-03-21 10:39:09 +00:00
|
|
|
echo "SUCCESS! Created snapshot ${TAG} of ${disk_img}"
|
2020-03-20 18:17:53 +00:00
|
|
|
else
|
2020-03-21 10:39:09 +00:00
|
|
|
echo "ERROR! Failed to create snapshot ${TAG} of ${disk_img}"
|
2020-03-20 18:17:53 +00:00
|
|
|
fi
|
2020-03-15 23:13:25 +00:00
|
|
|
else
|
2020-03-20 18:17:53 +00:00
|
|
|
echo "NOTE! ${disk_img} not found. Doing nothing."
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
function snapshot_delete() {
|
2020-03-21 10:39:09 +00:00
|
|
|
local TAG="${1}"
|
|
|
|
if [ -z "${TAG}" ]; then
|
2020-03-20 18:17:53 +00:00
|
|
|
echo "ERROR! No snapshot tag provided."
|
|
|
|
exit
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -e "${disk_img}" ]; then
|
2021-09-07 11:35:33 +00:00
|
|
|
if ${QEMU_IMG} snapshot -q -d "${TAG}" "${disk_img}"; then
|
2020-03-21 10:39:09 +00:00
|
|
|
echo "SUCCESS! Deleted snapshot ${TAG} of ${disk_img}"
|
2020-03-20 18:17:53 +00:00
|
|
|
else
|
2020-03-21 10:39:09 +00:00
|
|
|
echo "ERROR! Failed to delete snapshot ${TAG} of ${disk_img}"
|
2020-03-20 18:17:53 +00:00
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo "NOTE! ${disk_img} not found. Doing nothing."
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
function snapshot_info() {
|
|
|
|
if [ -e "${disk_img}" ]; then
|
|
|
|
${QEMU_IMG} info "${disk_img}"
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2020-03-19 17:28:13 +00:00
|
|
|
function get_port() {
|
2020-06-12 16:34:19 +00:00
|
|
|
local PORT_START=$1
|
|
|
|
local PORT_RANGE=$2
|
2020-03-19 17:28:13 +00:00
|
|
|
while true; do
|
2021-09-06 14:29:37 +00:00
|
|
|
local CANDIDATE=$((PORT_START + (RANDOM % PORT_RANGE)))
|
2020-03-19 17:28:13 +00:00
|
|
|
(echo "" >/dev/tcp/127.0.0.1/${CANDIDATE}) >/dev/null 2>&1
|
|
|
|
if [ $? -ne 0 ]; then
|
|
|
|
echo "${CANDIDATE}"
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2021-09-06 14:30:01 +00:00
|
|
|
function enable_usb_passthrough() {
|
2020-03-22 17:39:51 +00:00
|
|
|
local DEVICE=""
|
|
|
|
local USB_BUS=""
|
|
|
|
local USB_DEV=""
|
|
|
|
local USB_NAME=""
|
|
|
|
local VENDOR_ID=""
|
|
|
|
local PRODUCT_ID=""
|
2021-09-06 14:29:37 +00:00
|
|
|
local TEMP_SCRIPT=""
|
2020-03-22 17:39:51 +00:00
|
|
|
local EXEC_SCRIPT=0
|
|
|
|
|
2021-09-06 14:29:37 +00:00
|
|
|
TEMP_SCRIPT=$(mktemp)
|
2020-03-22 17:39:51 +00:00
|
|
|
# Have any USB devices been requested for pass-through?
|
|
|
|
if (( ${#usb_devices[@]} )); then
|
|
|
|
echo " - USB: Device pass-through requested:"
|
|
|
|
echo "#!/usr/bin/env bash" > "${TEMP_SCRIPT}"
|
|
|
|
for DEVICE in "${usb_devices[@]}"; do
|
2021-09-07 11:35:33 +00:00
|
|
|
VENDOR_ID=$(echo "${DEVICE}" | cut -d':' -f1)
|
|
|
|
PRODUCT_ID=$(echo "${DEVICE}" | cut -d':' -f2)
|
|
|
|
USB_BUS=$(lsusb -d "${VENDOR_ID}:${PRODUCT_ID}" | cut -d' ' -f2)
|
|
|
|
USB_DEV=$(lsusb -d "${VENDOR_ID}:${PRODUCT_ID}" | cut -d' ' -f4 | cut -d':' -f1)
|
|
|
|
USB_NAME=$(lsusb -d "${VENDOR_ID}:${PRODUCT_ID}" | cut -d' ' -f7-)
|
2020-03-22 17:39:51 +00:00
|
|
|
echo " - ${USB_NAME}"
|
2020-04-04 11:54:30 +00:00
|
|
|
USB_PASSTHROUGH="${USB_PASSTHROUGH} -device usb-host,vendorid=0x${VENDOR_ID},productid=0x${PRODUCT_ID},bus=usb.0"
|
2021-09-06 14:29:37 +00:00
|
|
|
if [ ! -w "/dev/bus/usb/${USB_BUS}/${USB_DEV}" ]; then
|
2020-03-22 17:39:51 +00:00
|
|
|
local EXEC_SCRIPT=1
|
|
|
|
echo "chown root:${USER} /dev/bus/usb/${USB_BUS}/${USB_DEV}" >> "${TEMP_SCRIPT}"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
if [ ${EXEC_SCRIPT} -eq 1 ]; then
|
|
|
|
chmod +x "${TEMP_SCRIPT}"
|
|
|
|
echo " Requested USB device(s) are NOT accessible."
|
|
|
|
echo " ${TEMP_SCRIPT} will be executed to enable access:"
|
|
|
|
echo
|
2021-09-06 14:29:37 +00:00
|
|
|
cat "${TEMP_SCRIPT}"
|
2020-03-22 17:39:51 +00:00
|
|
|
echo
|
2021-09-07 11:35:33 +00:00
|
|
|
if ! sudo "${TEMP_SCRIPT}"; then
|
2020-03-22 17:39:51 +00:00
|
|
|
echo " WARNING! Enabling USB device access failed."
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo " Requested USB device(s) are accessible."
|
|
|
|
fi
|
|
|
|
rm -f "${TEMP_SCRIPT}"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2020-03-15 23:13:25 +00:00
|
|
|
function vm_boot() {
|
2021-09-07 11:35:33 +00:00
|
|
|
local VMNAME=""
|
|
|
|
VMNAME=$(basename "${VM}" .conf)
|
|
|
|
local VMDIR=""
|
|
|
|
VMDIR=$(dirname "${disk_img}")
|
2021-09-25 12:13:26 +00:00
|
|
|
local CPU=""
|
2020-03-21 16:56:59 +00:00
|
|
|
local DISPLAY_DEVICE=""
|
2020-03-20 21:48:27 +00:00
|
|
|
local GL="on"
|
2021-09-25 12:13:26 +00:00
|
|
|
local GUEST_TWEAKS=""
|
|
|
|
local OSK=""
|
2021-09-07 11:35:33 +00:00
|
|
|
local QEMU_VER=""
|
2021-09-25 12:13:26 +00:00
|
|
|
local VIDEO=""
|
2021-09-07 11:35:33 +00:00
|
|
|
QEMU_VER=$(${QEMU} -version | head -n1 | cut -d' ' -f4 | cut -d'(' -f1)
|
2020-03-20 01:49:43 +00:00
|
|
|
echo "Starting ${VM}"
|
2020-03-19 23:17:45 +00:00
|
|
|
echo " - QEMU: ${QEMU} v${QEMU_VER}"
|
|
|
|
|
2020-03-21 11:59:33 +00:00
|
|
|
# Force to lowercase.
|
2021-09-07 11:35:33 +00:00
|
|
|
boot=${boot,,}
|
2020-04-04 11:54:30 +00:00
|
|
|
|
2020-05-06 19:23:30 +00:00
|
|
|
# Always Boot macOS using EFI
|
2020-04-04 11:54:30 +00:00
|
|
|
if [ "${guest_os}" == "macos" ]; then
|
|
|
|
boot="efi"
|
|
|
|
fi
|
|
|
|
|
2020-03-21 11:59:33 +00:00
|
|
|
if [ "${boot}" == "efi" ] || [ "${boot}" == "uefi" ]; then
|
2021-09-06 21:21:06 +00:00
|
|
|
if [ -e "/usr/share/OVMF/OVMF_CODE_4M.fd" ] ; then
|
2020-04-04 11:54:30 +00:00
|
|
|
if [ "${guest_os}" == "macos" ]; then
|
|
|
|
web_get "https://github.com/foxlet/macOS-Simple-KVM/raw/master/ESP.qcow2"
|
|
|
|
web_get "https://github.com/foxlet/macOS-Simple-KVM/raw/master/firmware/OVMF_CODE.fd"
|
|
|
|
web_get "https://github.com/foxlet/macOS-Simple-KVM/raw/master/firmware/OVMF_VARS-1024x768.fd"
|
|
|
|
local EFI_CODE="${VMDIR}/OVMF_CODE.fd"
|
|
|
|
local EFI_VARS="${VMDIR}/OVMF_VARS-1024x768.fd"
|
|
|
|
else
|
2021-09-06 21:21:06 +00:00
|
|
|
local EFI_CODE="/usr/share/OVMF/OVMF_CODE_4M.fd"
|
2020-04-04 11:54:30 +00:00
|
|
|
local EFI_VARS="${VMDIR}/${VMNAME}-vars.fd"
|
|
|
|
if [ ! -e "${EFI_VARS}" ]; then
|
2021-09-06 21:21:06 +00:00
|
|
|
cp "/usr/share/OVMF/OVMF_VARS_4M.fd" "${EFI_VARS}"
|
2020-04-04 11:54:30 +00:00
|
|
|
fi
|
2020-03-20 13:50:01 +00:00
|
|
|
fi
|
2020-03-21 11:59:33 +00:00
|
|
|
echo " - BOOT: EFI"
|
2020-03-19 03:07:52 +00:00
|
|
|
else
|
2020-03-21 11:59:33 +00:00
|
|
|
echo " - BOOT: Legacy BIOS"
|
|
|
|
echo " - EFI Booting requested but no EFI firmware found."
|
2020-03-19 03:07:52 +00:00
|
|
|
fi
|
|
|
|
else
|
2020-03-21 11:59:33 +00:00
|
|
|
echo " - BOOT: Legacy BIOS"
|
2020-03-19 03:07:52 +00:00
|
|
|
fi
|
|
|
|
|
2020-03-21 11:39:31 +00:00
|
|
|
# Force to lowercase.
|
2021-09-07 11:35:33 +00:00
|
|
|
guest_os=${guest_os,,}
|
2020-03-21 10:34:21 +00:00
|
|
|
# Make any OS specific adjustments
|
|
|
|
case ${guest_os} in
|
|
|
|
linux)
|
2021-09-25 12:13:26 +00:00
|
|
|
CPU="-cpu host,kvm=on"
|
2020-03-21 10:34:21 +00:00
|
|
|
;;
|
2020-04-04 11:54:30 +00:00
|
|
|
macos)
|
|
|
|
CPU="-cpu Penryn,vendor=GenuineIntel,kvm=on,+aes,+avx,+avx2,+bmi1,+bmi2,+fma,+invtsc,+movbe,+pcid,+smep,+sse3,+sse4.2,+xgetbv1,+xsave,+xsavec,+xsaveopt"
|
2021-09-07 11:35:33 +00:00
|
|
|
OSK=$(echo "bheuneqjbexolgurfrjbeqfthneqrqcyrnfrqbagfgrny(p)NccyrPbzchgreVap" | rot13)
|
2020-04-04 11:54:30 +00:00
|
|
|
GUEST_TWEAKS="-device isa-applesmc,osk=${OSK}"
|
|
|
|
;;
|
2020-03-21 10:34:21 +00:00
|
|
|
windows)
|
2021-09-25 12:13:26 +00:00
|
|
|
CPU="-cpu host,kvm=on,hv_time"
|
2020-03-21 15:22:01 +00:00
|
|
|
GUEST_TWEAKS="-no-hpet"
|
2020-03-21 10:34:21 +00:00
|
|
|
;;
|
|
|
|
*)
|
2021-09-25 12:13:26 +00:00
|
|
|
CPU="-cpu host,kvm=on"
|
2021-09-07 11:37:59 +00:00
|
|
|
echo "WARNING! Unrecognised guest OS: ${guest_os}"
|
2020-03-21 10:34:21 +00:00
|
|
|
;;
|
|
|
|
esac
|
2020-03-21 12:00:49 +00:00
|
|
|
echo " - Guest: ${guest_os^} optimised"
|
2020-03-21 10:34:21 +00:00
|
|
|
|
2020-03-19 23:20:46 +00:00
|
|
|
echo " - Disk: ${disk_img} (${disk})"
|
2020-03-20 14:22:22 +00:00
|
|
|
if [ ! -f "${disk_img}" ]; then
|
2020-03-21 10:29:48 +00:00
|
|
|
# If there is no disk image, create a new image.
|
2020-03-22 17:23:46 +00:00
|
|
|
mkdir -p "${VMDIR}" 2>/dev/null
|
2021-09-07 11:35:33 +00:00
|
|
|
if ! ${QEMU_IMG} create -q -f qcow2 "${disk_img}" "${disk}"; then
|
2020-03-22 17:23:46 +00:00
|
|
|
echo "ERROR! Failed to create ${disk_img}"
|
|
|
|
exit 1
|
|
|
|
fi
|
2020-04-04 11:54:30 +00:00
|
|
|
if [ -z "${iso}" ] && [ -z "${img}" ]; then
|
|
|
|
echo "ERROR! You haven't specified a .iso or .img image to boot from."
|
2020-03-21 10:29:48 +00:00
|
|
|
exit 1
|
|
|
|
fi
|
2020-04-04 11:54:30 +00:00
|
|
|
echo " Just created, booting from ${iso}${img}"
|
2020-03-22 17:23:46 +00:00
|
|
|
elif [ -e "${disk_img}" ]; then
|
2020-03-20 18:16:51 +00:00
|
|
|
# Check there isn't already a process attached to the disk image.
|
2021-09-07 11:35:33 +00:00
|
|
|
if ! ${QEMU_IMG} info "${disk_img}" >/dev/null; then
|
|
|
|
echo " Failed to get \"write\" lock. Is another process using the disk?"
|
2020-03-20 18:16:51 +00:00
|
|
|
exit 1
|
2020-03-20 15:31:24 +00:00
|
|
|
else
|
2020-03-21 10:43:00 +00:00
|
|
|
DISK_CURR_SIZE=$(stat -c%s "${disk_img}")
|
2021-09-07 11:35:33 +00:00
|
|
|
if [ "${DISK_CURR_SIZE}" -le "${DISK_MIN_SIZE}" ]; then
|
2020-04-04 11:54:30 +00:00
|
|
|
echo " Looks unused, booting from ${iso}${img}"
|
|
|
|
if [ -z "${iso}" ] && [ -z "${img}" ]; then
|
|
|
|
echo "ERROR! You haven't specified a .iso or .img image to boot from."
|
2020-03-21 10:29:48 +00:00
|
|
|
exit 1
|
|
|
|
fi
|
2020-03-20 18:16:51 +00:00
|
|
|
else
|
|
|
|
# If there is a disk image, that appears to have an install
|
2020-04-04 11:54:30 +00:00
|
|
|
# then do not boot from the iso/img
|
2020-03-20 18:16:51 +00:00
|
|
|
iso=""
|
2020-04-04 11:54:30 +00:00
|
|
|
img=""
|
2020-03-20 18:16:51 +00:00
|
|
|
fi
|
2020-03-20 15:31:24 +00:00
|
|
|
fi
|
2020-03-19 03:07:52 +00:00
|
|
|
fi
|
|
|
|
|
2020-03-20 18:35:29 +00:00
|
|
|
# Has the status quo been requested?
|
2020-03-21 10:57:27 +00:00
|
|
|
if [ "${STATUS_QUO}" == "-snapshot" ] && [ -z "${iso}" ]; then
|
2020-03-20 18:35:29 +00:00
|
|
|
echo " Existing disk state will be preserved, no writes will be committed."
|
|
|
|
fi
|
|
|
|
|
2020-03-21 00:11:04 +00:00
|
|
|
if [ -n "${iso}" ] && [ -e "${iso}" ]; then
|
|
|
|
echo " - Boot: ${iso}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -n "${driver_iso}" ] && [ -e "${driver_iso}" ]; then
|
|
|
|
echo " - Drivers: ${driver_iso}"
|
|
|
|
fi
|
|
|
|
|
2020-03-21 10:46:38 +00:00
|
|
|
local CORES_VM="1"
|
2020-04-12 22:30:11 +00:00
|
|
|
if [ -z "$cpu_cores" ]; then
|
2021-09-07 11:35:33 +00:00
|
|
|
local CORES_HOST=""
|
|
|
|
CORES_HOST=$(nproc --all)
|
|
|
|
if [ "${CORES_HOST}" -ge 32 ]; then
|
2021-09-06 14:30:41 +00:00
|
|
|
CORES_VM="16"
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${CORES_HOST}" -ge 16 ]; then
|
2021-09-06 14:30:41 +00:00
|
|
|
CORES_VM="8"
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${CORES_HOST}" -ge 8 ]; then
|
2020-04-12 22:30:11 +00:00
|
|
|
CORES_VM="4"
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${CORES_HOST}" -ge 4 ]; then
|
2020-04-12 22:30:11 +00:00
|
|
|
CORES_VM="2"
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
CORES_VM="$cpu_cores"
|
2020-03-19 02:12:36 +00:00
|
|
|
fi
|
2020-04-04 11:54:30 +00:00
|
|
|
local SMP="-smp ${CORES_VM},sockets=1,cores=${CORES_VM},threads=1"
|
2020-03-21 10:46:38 +00:00
|
|
|
echo " - CPU: ${CORES_VM} Core(s)"
|
2020-03-19 02:12:36 +00:00
|
|
|
|
2020-03-21 10:49:42 +00:00
|
|
|
local RAM_VM="2G"
|
2020-04-12 22:30:11 +00:00
|
|
|
if [ -z "$ram" ]; then
|
2021-09-07 11:35:33 +00:00
|
|
|
local RAM_HOST=""
|
|
|
|
RAM_HOST=$(free --mega -h | grep Mem | cut -d':' -f2 | cut -d'G' -f1 | sed 's/ //g')
|
2020-04-12 22:30:11 +00:00
|
|
|
#Round up - https://github.com/wimpysworld/quickemu/issues/11
|
2021-09-07 11:35:33 +00:00
|
|
|
RAM_HOST=$(printf '%.*f\n' 0 "${RAM_HOST}")
|
|
|
|
if [ "${RAM_HOST}" -ge 256 ]; then
|
2021-09-06 14:31:07 +00:00
|
|
|
RAM_VM="32G"
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${RAM_HOST}" -ge 128 ]; then
|
2021-09-06 14:31:07 +00:00
|
|
|
RAM_VM="16G"
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${RAM_HOST}" -ge 64 ]; then
|
2021-09-06 14:31:07 +00:00
|
|
|
RAM_VM="8G"
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${RAM_HOST}" -ge 32 ]; then
|
2020-04-12 22:30:11 +00:00
|
|
|
RAM_VM="4G"
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${RAM_HOST}" -ge 16 ]; then
|
2020-04-12 22:30:11 +00:00
|
|
|
RAM_VM="3G"
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
RAM_VM="$ram"
|
2020-03-19 02:12:36 +00:00
|
|
|
fi
|
2020-03-21 10:49:42 +00:00
|
|
|
echo " - RAM: ${RAM_VM}"
|
2020-03-19 01:45:38 +00:00
|
|
|
|
2020-03-21 10:52:09 +00:00
|
|
|
local X_RES=1152
|
|
|
|
local Y_RES=648
|
2020-03-20 01:49:43 +00:00
|
|
|
if [ "${XDG_SESSION_TYPE}" == "x11" ]; then
|
2021-09-07 11:35:33 +00:00
|
|
|
local LOWEST_WIDTH=""
|
2021-09-23 20:34:21 +00:00
|
|
|
if [ -z "${SCREEN}" ]; then
|
|
|
|
LOWEST_WIDTH=$(xrandr --listmonitors | grep -v Monitors | cut -d' ' -f4 | cut -d'/' -f1 | sort | head -n1)
|
|
|
|
else
|
|
|
|
LOWEST_WIDTH=$(xrandr --listmonitors | grep -v Monitors | grep "^ ${SCREEN}:" | cut -d' ' -f4 | cut -d'/' -f1 | head -n1)
|
|
|
|
fi
|
2021-09-07 11:35:33 +00:00
|
|
|
if [ "${FULLSCREEN}" ]; then
|
2021-09-23 20:34:21 +00:00
|
|
|
if [ -z "${SCREEN}" ]; then
|
|
|
|
X_RES=$(xrandr --listmonitors | grep -v Monitors | cut -d' ' -f4 | cut -d'/' -f1 | sort | head -n1)
|
|
|
|
Y_RES=$(xrandr --listmonitors | grep -v Monitors | cut -d' ' -f4 | cut -d'/' -f2 | cut -d'x' -f2 | sort | head -n1)
|
|
|
|
else
|
|
|
|
X_RES=$(xrandr --listmonitors | grep -v Monitors | grep "^ ${SCREEN}:" | cut -d' ' -f4 | cut -d'/' -f1 | head -n1)
|
|
|
|
Y_RES=$(xrandr --listmonitors | grep -v Monitors | grep "^ ${SCREEN}:" | cut -d' ' -f4 | cut -d'/' -f2 | cut -d'x' -f2 | head -n1)
|
|
|
|
fi
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${LOWEST_WIDTH}" -ge 3840 ]; then
|
2020-03-21 10:52:09 +00:00
|
|
|
X_RES=3200
|
|
|
|
Y_RES=1800
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${LOWEST_WIDTH}" -ge 2560 ]; then
|
2020-03-21 10:52:09 +00:00
|
|
|
X_RES=2048
|
|
|
|
Y_RES=1152
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${LOWEST_WIDTH}" -ge 1920 ]; then
|
2020-03-21 10:52:09 +00:00
|
|
|
X_RES=1664
|
|
|
|
Y_RES=936
|
2021-09-07 11:35:33 +00:00
|
|
|
elif [ "${LOWEST_WIDTH}" -ge 1280 ]; then
|
2020-03-21 10:52:09 +00:00
|
|
|
X_RES=1152
|
|
|
|
Y_RES=648
|
2020-03-20 01:49:43 +00:00
|
|
|
fi
|
2020-03-19 01:45:38 +00:00
|
|
|
fi
|
2020-03-20 21:48:27 +00:00
|
|
|
|
2021-09-25 12:13:26 +00:00
|
|
|
echo " - Screen: ${X_RES}x${Y_RES}"
|
|
|
|
echo " - Display: ${OUTPUT^^}"
|
|
|
|
|
|
|
|
# https://www.kraxel.org/blog/2019/09/display-devices-in-qemu/
|
|
|
|
if [ "${guest_os}" == "linux" ]; then
|
|
|
|
DISPLAY_DEVICE="virtio-vga"
|
|
|
|
elif [ "${guest_os}" == "macos" ]; then
|
|
|
|
DISPLAY_DEVICE="VGA"
|
|
|
|
#DISPLAY_DEVICE="bochs-display"
|
|
|
|
elif [ "${guest_os}" == "windows" ]; then
|
|
|
|
DISPLAY_DEVICE="qxl-vga"
|
2020-03-20 21:48:27 +00:00
|
|
|
else
|
2021-09-25 12:13:26 +00:00
|
|
|
DISPLAY_DEVICE="qxl-vga"
|
2020-03-20 21:48:27 +00:00
|
|
|
fi
|
2020-03-21 16:56:59 +00:00
|
|
|
|
2021-09-25 12:30:56 +00:00
|
|
|
if [ "${OUTPUT}" == "spice" ]; then
|
|
|
|
if [ "${guest_os}" != "macos" ]; then
|
|
|
|
DISPLAY_DEVICE="qxl-vga"
|
|
|
|
fi
|
|
|
|
OUTPUT="none"
|
|
|
|
fi
|
|
|
|
|
2021-09-25 12:13:26 +00:00
|
|
|
echo " - Video: ${DISPLAY_DEVICE}"
|
|
|
|
|
|
|
|
# Allocate VRAM to VGA devices
|
2021-09-06 21:23:10 +00:00
|
|
|
if [ "${DISPLAY_DEVICE}" == "qxl-vga" ] || [ "${DISPLAY_DEVICE}" == "VGA" ]; then
|
2021-09-25 12:13:26 +00:00
|
|
|
VIDEO="-device ${DISPLAY_DEVICE},xres=${X_RES},yres=${Y_RES},vgamem_mb=128 ${FULLSCREEN}"
|
2020-03-21 01:33:56 +00:00
|
|
|
else
|
2021-09-23 17:40:45 +00:00
|
|
|
VIDEO="-device ${DISPLAY_DEVICE},xres=${X_RES},yres=${Y_RES} ${FULLSCREEN}"
|
2020-03-21 01:33:56 +00:00
|
|
|
fi
|
2020-03-21 16:56:59 +00:00
|
|
|
|
2021-09-25 12:13:26 +00:00
|
|
|
if [ "${OUTPUT}" == "gtk" ]; then
|
|
|
|
OUTPUT="${OUTPUT},grab-on-hover=on,zoom-to-fit=off"
|
2021-09-25 12:08:56 +00:00
|
|
|
# GL is not working with GTK and virtio-vga
|
2021-09-25 12:13:26 +00:00
|
|
|
if [ "${DISPLAY_DEVICE}" == "virtio-vga" ]; then
|
|
|
|
GL="off"
|
|
|
|
fi
|
|
|
|
fi
|
2020-03-20 20:35:11 +00:00
|
|
|
|
2021-09-25 12:13:26 +00:00
|
|
|
if [ "${OUTPUT}" != "none" ]; then
|
|
|
|
OUTPUT="${OUTPUT},gl=${GL}"
|
2020-03-19 01:39:23 +00:00
|
|
|
fi
|
2021-09-25 12:13:26 +00:00
|
|
|
echo " - GL: ${GL^^}"
|
2020-03-19 01:39:23 +00:00
|
|
|
|
2021-09-25 12:08:56 +00:00
|
|
|
if [ "${GL}" == "on" ] && [ "${DISPLAY_DEVICE}" == "virtio-vga" ]; then
|
|
|
|
DISPLAY_DEVICE="${DISPLAY_DEVICE},virgl=on"
|
|
|
|
echo " - Virgil3D: ON"
|
2020-03-19 01:39:23 +00:00
|
|
|
else
|
2021-09-25 12:08:56 +00:00
|
|
|
echo " - Virgil3D: OFF"
|
2020-03-19 01:39:23 +00:00
|
|
|
fi
|
|
|
|
|
2021-09-25 12:13:26 +00:00
|
|
|
# Set the hostname of the VM
|
|
|
|
local NET="user,hostname=${VMNAME}"
|
|
|
|
|
2020-03-19 17:29:01 +00:00
|
|
|
# Find a free port to expose ssh to the guest
|
2021-09-25 12:14:32 +00:00
|
|
|
local SSH_PORT=""
|
|
|
|
SSH_PORT=$(get_port 22220 9)
|
|
|
|
if [ -n "${SSH_PORT}" ]; then
|
|
|
|
NET="${NET},hostfwd=tcp::${SSH_PORT}-:22"
|
|
|
|
echo " - ssh: ${SSH_PORT}/tcp is connected. Login via 'ssh user@localhost -p ${SSH_PORT}'"
|
2020-03-19 17:29:01 +00:00
|
|
|
else
|
|
|
|
echo " - ssh: All ports for exposing ssh have been exhausted."
|
|
|
|
fi
|
|
|
|
|
2020-08-10 11:15:18 +00:00
|
|
|
# Have any port forwards been requested?
|
|
|
|
if (( ${#port_forwards[@]} )); then
|
|
|
|
echo " - PORTS: Port forwards requested:"
|
|
|
|
for FORWARD in "${port_forwards[@]}"; do
|
2021-09-07 11:35:33 +00:00
|
|
|
HOST_PORT=$(echo "${FORWARD}" | cut -d':' -f1)
|
|
|
|
GUEST_PORT=$(echo "${FORWARD}" | cut -d':' -f2)
|
2020-08-10 11:15:18 +00:00
|
|
|
echo " - ${HOST_PORT} => ${GUEST_PORT}"
|
|
|
|
NET="${NET},hostfwd=tcp::${HOST_PORT}-:${GUEST_PORT}"
|
|
|
|
done
|
|
|
|
fi
|
|
|
|
|
2020-06-12 16:34:19 +00:00
|
|
|
# Find a free port for spice
|
2021-09-25 12:30:56 +00:00
|
|
|
local SPICE="disable-ticketing=on"
|
2021-09-07 11:35:33 +00:00
|
|
|
local SPICE_PORT=""
|
|
|
|
SPICE_PORT=$(get_port 5930 9)
|
|
|
|
if [ -z "${SPICE_PORT}" ]; then
|
2021-09-25 12:30:56 +00:00
|
|
|
echo " - SPICE: All spice ports have been exhausted."
|
|
|
|
if [ "${OUTPUT}" == "none" ] || [ "${OUTPUT}" == "spice-app" ]; then
|
|
|
|
echo " ERROR! Requested SPICE display, but no SPICE ports are free."
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
if [ "${OUTPUT}" == "spice-app" ]; then
|
|
|
|
echo " - SPICE: Enabled"
|
|
|
|
else
|
|
|
|
echo " - SPICE: ${SPICE_PORT}/tcp is connected. Login via 'spicy --title \"${VMNAME}\" --port ${SPICE_PORT} --spice-shared-dir ${HOME}' ${FULLSPICY}"
|
|
|
|
SPICE="${SPICE},port=${SPICE_PORT}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Reference: https://gitlab.gnome.org/GNOME/phodav/-/issues/5
|
|
|
|
if [ "${guest_os}" != "macos" ]; then
|
|
|
|
echo " - WebDAV: ${HOME} will be exported to ${VMNAME} via dav://localhost:9843/"
|
|
|
|
fi
|
2020-06-12 16:34:19 +00:00
|
|
|
fi
|
|
|
|
|
2020-03-22 17:39:51 +00:00
|
|
|
enable_usb_passthrough
|
|
|
|
|
2021-09-25 12:35:02 +00:00
|
|
|
# Build the VM configuration
|
|
|
|
local DISKS=""
|
|
|
|
local NET_DEVICE=""
|
|
|
|
local SMARTCARD=""
|
|
|
|
local USB_HOSTPASS=""
|
|
|
|
local USB_SPICEPASS=""
|
|
|
|
|
|
|
|
if [ "${guest_os}" == "macos" ]; then
|
|
|
|
DISKS="-drive if=pflash,format=raw,readonly=on,file=${EFI_CODE}
|
|
|
|
-drive if=pflash,format=raw,file=${EFI_VARS}
|
|
|
|
-drive id=ESP,cache=directsync,aio=native,if=none,format=qcow2,file=${VMDIR}/ESP.qcow2"
|
|
|
|
if [ -n "${img}" ]; then
|
|
|
|
DISKS="${DISKS}
|
|
|
|
-drive id=InstallMedia,cache=directsync,aio=native,if=none,format=raw,readonly=on,file=${img}
|
|
|
|
-device virtio-blk-pci,drive=InstallMedia,scsi=off"
|
2021-09-06 21:26:48 +00:00
|
|
|
fi
|
2021-09-25 12:35:02 +00:00
|
|
|
DISKS="${DISKS}
|
|
|
|
-device virtio-blk-pci,drive=ESP,scsi=off
|
|
|
|
-drive id=SystemDisk,cache=directsync,aio=native,if=none,format=qcow2,file=${disk_img} ${STATUS_QUO}
|
|
|
|
-device virtio-blk-pci,drive=SystemDisk,scsi=off"
|
|
|
|
NET_DEVICE="vmxnet3"
|
|
|
|
# UNTESTED! USB2 passthrough since USB3 isn't(?) supported in macOS VMs
|
|
|
|
# USB_SPICEPASS="
|
|
|
|
# -device usb-ehci,id=spicepass
|
|
|
|
# -device ich9-usb-uhci1,masterbus=spicepass.0,firstport=0,multifunction=on
|
|
|
|
# -device ich9-usb-uhci2,masterbus=spicepass.0,firstport=2
|
|
|
|
# -device ich9-usb-uhci3,masterbus=spicepass.0,firstport=4
|
|
|
|
# -chardev spicevmc,name=usbredir,id=usbredirchardev1
|
|
|
|
# -device usb-redir,chardev=usbredirchardev1,id=usbredirdev1
|
|
|
|
# -chardev spicevmc,name=usbredir,id=usbredirchardev2
|
|
|
|
# -device usb-redir,chardev=usbredirchardev2,id=usbredirdev2
|
|
|
|
# -chardev spicevmc,name=usbredir,id=usbredirchardev3
|
|
|
|
# -device usb-redir,chardev=usbredirchardev3,id=usbredirdev3"
|
|
|
|
USB_HOSTPASS="-device usb-ehci,id=hostpass
|
|
|
|
${USB_PASSTHROUGH}"
|
2020-03-22 17:23:46 +00:00
|
|
|
else
|
2021-09-25 12:35:02 +00:00
|
|
|
if [ "${boot}" == "efi" ] || [ "${boot}" == "uefi" ]; then
|
|
|
|
DISKS="-drive if=pflash,format=raw,readonly=on,file=${EFI_CODE}
|
|
|
|
-drive if=pflash,format=raw,file=${EFI_VARS}"
|
|
|
|
fi
|
|
|
|
DISKS="${DISKS}
|
|
|
|
-drive media=cdrom,index=0,file=${iso}
|
|
|
|
-drive media=cdrom,index=1,file=${driver_iso}
|
|
|
|
-drive if=none,id=drive0,cache=directsync,aio=native,format=qcow2,file=${disk_img}
|
|
|
|
-device virtio-blk-pci,drive=drive0,scsi=off ${STATUS_QUO}"
|
|
|
|
NET_DEVICE="virtio-net"
|
|
|
|
SMARTCARD="-device usb-ccid
|
|
|
|
-chardev spicevmc,id=ccid,name=smartcard
|
|
|
|
-device ccid-card-passthru,chardev=ccid"
|
|
|
|
USB_SPICEPASS="-device qemu-xhci,id=spicepass
|
|
|
|
-chardev spicevmc,id=usbredirchardev1,name=usbredir
|
|
|
|
-device usb-redir,chardev=usbredirchardev1,id=usbredirdev1
|
|
|
|
-chardev spicevmc,id=usbredirchardev2,name=usbredir
|
|
|
|
-device usb-redir,chardev=usbredirchardev2,id=usbredirdev2
|
|
|
|
-chardev spicevmc,id=usbredirchardev3,name=usbredir
|
|
|
|
-device usb-redir,chardev=usbredirchardev3,id=usbredirdev3"
|
|
|
|
USB_HOSTPASS="-device qemu-xhci,id=hostpass
|
|
|
|
${USB_PASSTHROUGH}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Boot the VM
|
|
|
|
${QEMU} \
|
|
|
|
-name ${VMNAME},process=${VMNAME} \
|
|
|
|
-enable-kvm -machine q35,vmport=off ${GUEST_TWEAKS} \
|
|
|
|
${CPU} ${SMP} \
|
|
|
|
-m ${RAM_VM} -device virtio-balloon \
|
|
|
|
${DISKS} \
|
|
|
|
${VIDEO} -display ${OUTPUT} \
|
|
|
|
-device usb-ehci,id=input \
|
|
|
|
-device usb-kbd,bus=input.0 \
|
|
|
|
-device usb-tablet,bus=input.0 \
|
|
|
|
${USB_SPICEPASS} \
|
|
|
|
${USB_HOSTPASS} \
|
|
|
|
${SMARTCARD} \
|
|
|
|
-device ${NET_DEVICE},netdev=nic -netdev ${NET},id=nic \
|
|
|
|
-audiodev pa,id=pa,out.stream-name=${LAUNCHER}-${VMNAME},in.stream-name=${LAUNCHER}-${VMNAME} \
|
|
|
|
-device intel-hda -device hda-duplex,audiodev=pa,mixer=off \
|
|
|
|
-rtc base=localtime,clock=host \
|
|
|
|
-object rng-random,id=rng0,filename=/dev/urandom \
|
|
|
|
-device virtio-rng-pci,rng=rng0 \
|
|
|
|
-spice ${SPICE} \
|
|
|
|
-device virtio-serial-pci \
|
|
|
|
-chardev spicevmc,id=vdagent0,name=vdagent \
|
|
|
|
-device virtserialport,chardev=vdagent0,name=com.redhat.spice.0 \
|
|
|
|
-device virtio-serial-pci \
|
|
|
|
-chardev spiceport,id=webdav0,name=org.spice-space.webdav.0 \
|
|
|
|
-device virtserialport,chardev=webdav0,name=org.spice-space.webdav.0 \
|
|
|
|
-serial mon:stdio > "${VMDIR}/${VMNAME}.log" &
|
2021-09-25 12:30:56 +00:00
|
|
|
echo " - PID: ${!}"
|
|
|
|
|
|
|
|
# If output is 'none' then SPICE was requested.
|
|
|
|
if [ ${OUTPUT} == "none" ]; then
|
|
|
|
spicy --title "${VMNAME}" --port ${SPICE_PORT} ${FULLSPICY} --spice-shared-dir "${HOME}" >/dev/null 2>&1
|
2021-09-06 21:26:48 +00:00
|
|
|
fi
|
2020-03-15 23:13:25 +00:00
|
|
|
}
|
|
|
|
|
2020-04-02 22:23:12 +00:00
|
|
|
function shortcut_create {
|
2021-09-07 11:35:33 +00:00
|
|
|
local VMNAME=""
|
|
|
|
VMNAME=$(basename "${VM}" .conf)
|
|
|
|
local LAUNCHER_DIR=""
|
|
|
|
LAUNCHER_DIR="$(dirname "$(realpath "$0")")"
|
2020-04-02 22:23:12 +00:00
|
|
|
local filename="/home/${USER}/.local/share/applications/${VMNAME}.desktop"
|
2021-09-07 11:35:33 +00:00
|
|
|
cat << EOF > "${filename}"
|
2020-04-02 22:23:12 +00:00
|
|
|
[Desktop Entry]
|
|
|
|
Version=1.0
|
|
|
|
Type=Application
|
|
|
|
Terminal=true
|
|
|
|
Exec=${LAUNCHER_DIR}/${LAUNCHER} --vm ${VM}
|
|
|
|
Name=${VMNAME}
|
2021-09-06 21:21:06 +00:00
|
|
|
Icon=/usr/share/icons/hicolor/scalable/apps/qemu.svg
|
2020-04-02 22:23:12 +00:00
|
|
|
EOF
|
|
|
|
echo "Created ${VMNAME}.desktop file"
|
|
|
|
}
|
|
|
|
|
2020-03-15 23:13:25 +00:00
|
|
|
function usage() {
|
|
|
|
echo
|
|
|
|
echo "Usage"
|
|
|
|
echo " ${LAUNCHER} --vm ubuntu.conf"
|
|
|
|
echo
|
|
|
|
echo "You can also pass optional parameters"
|
2020-03-20 18:22:03 +00:00
|
|
|
echo " --delete : Delete the disk image."
|
2021-09-25 12:30:56 +00:00
|
|
|
echo " --display : Select display backend. 'sdl' (default), 'gtk' or 'spice'"
|
2020-04-02 22:23:12 +00:00
|
|
|
echo " --shortcut : Create a desktop shortcut"
|
2020-03-20 18:22:03 +00:00
|
|
|
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."
|
2020-03-20 18:35:29 +00:00
|
|
|
echo " --status-quo : Do not commit any changes to disk/snapshot."
|
2020-08-10 11:17:06 +00:00
|
|
|
echo " --fullscreen : Starts VM in full screen mode"
|
2020-10-20 08:49:56 +00:00
|
|
|
echo " --no-smb : Do not expose the home directory via SMB."
|
2020-03-15 23:13:25 +00:00
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
2020-03-21 11:05:31 +00:00
|
|
|
# Lowercase variables are used in the VM config file only
|
2020-03-21 11:59:33 +00:00
|
|
|
boot="legacy"
|
2020-03-21 11:39:31 +00:00
|
|
|
guest_os="linux"
|
2020-04-04 11:54:30 +00:00
|
|
|
img=""
|
2020-03-21 10:28:43 +00:00
|
|
|
iso=""
|
|
|
|
driver_iso=""
|
|
|
|
disk_img=""
|
2020-03-21 11:40:20 +00:00
|
|
|
disk="64G"
|
2020-03-22 17:39:51 +00:00
|
|
|
usb_devices=()
|
2020-04-12 22:30:11 +00:00
|
|
|
ram=""
|
|
|
|
cpu_cores=""
|
2020-03-21 11:05:31 +00:00
|
|
|
|
2020-08-10 11:17:06 +00:00
|
|
|
FULLSCREEN=""
|
2021-09-25 12:30:56 +00:00
|
|
|
FULLSPICY=""
|
2020-03-15 23:13:25 +00:00
|
|
|
DELETE=0
|
2021-09-25 12:30:56 +00:00
|
|
|
OUTPUT="sdl"
|
2020-03-20 18:17:53 +00:00
|
|
|
SNAPSHOT_ACTION=""
|
|
|
|
SNAPSHOT_TAG=""
|
2020-03-21 10:57:27 +00:00
|
|
|
STATUS_QUO=""
|
2021-09-06 14:27:49 +00:00
|
|
|
USB_PASSTHROUGH=""
|
2020-03-15 23:13:25 +00:00
|
|
|
VM=""
|
2020-04-02 22:23:12 +00:00
|
|
|
SHORTCUT=0
|
2021-09-23 20:34:21 +00:00
|
|
|
SCREEN=""
|
2020-03-21 11:05:31 +00:00
|
|
|
|
2020-03-22 17:23:46 +00:00
|
|
|
readonly LAUNCHER=$(basename "${0}")
|
2020-03-21 10:41:25 +00:00
|
|
|
readonly DISK_MIN_SIZE=$((197632 * 8))
|
2021-09-06 21:21:06 +00:00
|
|
|
|
|
|
|
# TODO: Make this run the native architecture binary
|
|
|
|
QEMU=$(which qemu-system-x86_64)
|
|
|
|
QEMU_IMG=$(which qemu-img)
|
|
|
|
if [ ! -e "${QEMU}" ] && [ ! -e "${QEMU_IMG}" ]; then
|
|
|
|
echo "ERROR! qemu not found. Please install qemu."
|
|
|
|
exit 1
|
|
|
|
fi
|
2020-03-15 23:13:25 +00:00
|
|
|
|
2021-09-06 21:24:20 +00:00
|
|
|
QEMU_VER=$(${QEMU} -version | head -n1 | cut -d' ' -f4 | cut -d'(' -f1 | sed 's/\.//g')
|
2021-09-07 11:35:33 +00:00
|
|
|
if [ "${QEMU_VER}" -lt 600 ]; then
|
2021-09-10 12:25:37 +00:00
|
|
|
echo "ERROR! Qemu 6.0.0 or newer is required, detected $(${QEMU} -version | head -n1 | cut -d' ' -f4 | cut -d'(' -f1)."
|
2021-09-06 21:24:20 +00:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2020-08-10 12:07:45 +00:00
|
|
|
# Take command line arguments
|
|
|
|
if [ $# -lt 1 ]; then
|
|
|
|
usage
|
|
|
|
exit 0
|
|
|
|
else
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
case "${1}" in
|
|
|
|
-delete|--delete)
|
|
|
|
DELETE=1
|
|
|
|
shift;;
|
2021-09-25 12:30:56 +00:00
|
|
|
-display|--display)
|
|
|
|
OUTPUT="${2}"
|
|
|
|
if [ "${OUTPUT}" != "gtk" ] && [ "${OUTPUT}" != "sdl" ] && [ "${OUTPUT}" != "spice" ]; then
|
|
|
|
echo "ERROR! Requested output '${OUTPUT}' is not recognised."
|
|
|
|
exit 1
|
|
|
|
elif [ "${OUTPUT}" == "spice" ] && [ ! "$(which spicy)" ]; then
|
|
|
|
echo "ERROR! Requested SPICE display, but 'spicy' is not installed."
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
shift
|
|
|
|
shift;;
|
2020-08-10 12:07:45 +00:00
|
|
|
-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)
|
|
|
|
STATUS_QUO="-snapshot"
|
|
|
|
shift;;
|
2021-09-25 12:30:56 +00:00
|
|
|
-fullscreen|--fullscreen|-full-screen|--full-screen)
|
2021-09-23 17:40:45 +00:00
|
|
|
FULLSCREEN="-full-screen"
|
2021-09-25 12:30:56 +00:00
|
|
|
FULLSPICY="--full-screen"
|
2020-08-10 12:07:45 +00:00
|
|
|
shift;;
|
|
|
|
-vm|--vm)
|
|
|
|
VM="${2}"
|
|
|
|
shift
|
|
|
|
shift;;
|
2021-09-23 20:34:21 +00:00
|
|
|
-screen|--screen)
|
|
|
|
SCREEN="${2}"
|
|
|
|
shift
|
|
|
|
shift;;
|
2020-08-10 12:07:45 +00:00
|
|
|
-shortcut|--shortcut)
|
|
|
|
SHORTCUT=1
|
|
|
|
shift;;
|
|
|
|
-h|--h|-help|--help)
|
|
|
|
usage;;
|
|
|
|
*)
|
|
|
|
echo "ERROR! \"${1}\" is not a supported parameter."
|
|
|
|
usage;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
fi
|
2020-03-15 23:13:25 +00:00
|
|
|
|
2020-03-21 10:30:25 +00:00
|
|
|
if [ -n "${VM}" ] && [ -e "${VM}" ]; then
|
2021-09-07 11:35:33 +00:00
|
|
|
# shellcheck source=/dev/null
|
2020-03-20 01:49:43 +00:00
|
|
|
source "${VM}"
|
2020-03-20 18:16:08 +00:00
|
|
|
if [ -z "${disk_img}" ]; then
|
|
|
|
echo "ERROR! No disk_img defined."
|
|
|
|
exit 1
|
|
|
|
fi
|
2020-03-20 01:49:43 +00:00
|
|
|
else
|
|
|
|
echo "ERROR! Virtual machine configuration not found."
|
|
|
|
usage
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ${DELETE} -eq 1 ]; then
|
2020-03-20 15:34:18 +00:00
|
|
|
disk_delete
|
2020-03-20 18:17:53 +00:00
|
|
|
exit
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
|
|
|
|
2020-03-20 18:17:53 +00:00
|
|
|
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
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
|
|
|
|
2020-04-02 22:23:12 +00:00
|
|
|
if [ ${SHORTCUT} -eq 1 ]; then
|
|
|
|
shortcut_create
|
|
|
|
exit
|
|
|
|
fi
|
|
|
|
|
|
|
|
vm_boot
|