#!/usr/bin/env bash function os_support() { echo freebsd \ kubuntu \ lubuntu \ macos \ ubuntu \ ubuntu-budgie \ ubuntu-kylin \ ubuntu-mate \ ubuntu-studio \ windows \ xubuntu } function releases_freebsd(){ echo 12_2 \ 13_0 } function releases_macos() { echo high-sierra \ mojave \ catalina \ big-sur } function releases_ubuntu() { echo bionic \ focal \ hirsute \ devel } function languages_windows() { echo Arabic \ Brazilian Portuguese \ Bulgarian \ Chinese \(Simplified\) \ Chinese \(Traditional\) \ Croatian \ Czech \ Danish \ Dutch \ English \ English International \ Estonian \ Finnish \ French \ French Canadian \ German \ Greek \ Hebrew \ Hungarian \ Italian \ Japanese \ Korean \ Latvian \ Lithuanian \ Norwegian \ Polish \ Portuguese \ Romanian \ Russian \ Serbian Latin \ Slovak \ Slovenian \ Spanish \ Spanish \(Mexico\) \ Swedish \ Thai \ Turkish \ Ukrainian } function releases_windows() { echo 8 \ 10 \ 11 } function unattended_windows() { cat << 'EOF' > "${1}" true 0 true 1 EFI 100 2 MSR 512 3 Primary true 1 1 FAT32 2 3 C NTFS OnError OnError 0 3 true VK7JG-NPHTM-C97JM-9MPGT-3V66T Never true Never E:\amd64\w10 E:\viogpudo\w10\amd64 E:\viorng\w10\amd64 E:\NetKVM\w10\amd64 * Wimpys World Quickemu 24/7 Wimpys World https://github.com/wimpysworld/quickemu/issues Wimpys World true true EOF } function web_get() { local DIR="${2}" local FILE="" local URL="${1}" if [ -n "${3}" ]; then FILE="${3}" else FILE="${URL##*/}" fi mkdir -p "${DIR}" 2>/dev/null if ! wget --quiet --continue --show-progress --progress=bar:force:noscroll "${URL}" -O "${DIR}/${FILE}"; then echo "ERROR! Failed to download ${URL}. Try running 'quickget' again." exit 1 fi } function zsync_get() { local DIR="${2}" local FILE="" local OUT="" local URL="${1}" FILE="${URL##*/}" if [ -n "${3}" ]; then OUT="${3}" else OUT="${FILE}" fi mkdir -p "${DIR}" 2>/dev/null if ! zsync "${URL}.zsync" -i "${DIR}/${OUT}" -o "${DIR}/${OUT}"; then echo "ERROR! Failed to download ${URL}.zsync" exit 1 fi if [ -e "${DIR}/${FILE}.zs-old" ]; then rm -v "${DIR}/${FILE}.zs-old" fi } function make_vm_dir() { if ! mkdir -p "${VM_PATH}" 2>/dev/null; then echo "ERROR! Unable to create directory ${VM_PATH}" fi } function make_vm_config() { local IMAGE_FILE="" local ISO_FILE="" local IMAGE_TYPE="" local GUEST="" IMAGE_FILE="${1}" ISO_FILE="${2}" if [[ "${OS}" == "freebsd" ]]; then GUEST="freebsd" IMAGE_TYPE="iso" elif [[ "${OS}" == *"ubuntu"* ]]; then GUEST="linux" IMAGE_TYPE="iso" elif [ "${OS}" == "macos" ]; then GUEST="macos" IMAGE_TYPE="img" elif [ "${OS}" == "windows" ]; then GUEST="windows" IMAGE_TYPE="iso" fi if [ ! -e "${OS}-${RELEASE}.conf" ]; then echo "Making VM configuration for ${OS}-${RELEASE}..." cat << EOF > "${OS}-${RELEASE}.conf" guest_os="${GUEST}" disk_img="${VM_PATH}/disk.qcow2" ${IMAGE_TYPE}="${VM_PATH}/${IMAGE_FILE}" EOF if [ -n "${ISO_FILE}" ]; then echo "fixed_iso=\"${VM_PATH}/${ISO_FILE}\"" >> "${OS}-${RELEASE}.conf" fi if [ "${OS}" == "macos" ]; then echo "macos_release=\"${RELEASE}\"" >> "${OS}-${RELEASE}.conf" fi # Enable TPM for Windows 11 if [ "${OS}" == "windows" ] && [ ${RELEASE} -ge 11 ]; then echo "tpm=\"on\"" >> "${OS}-${RELEASE}.conf" fi fi } function start_vm_info() { echo echo "To start your ${OS} ${RELEASE} virtual machine run:" echo " quickemu --vm ${OS}-${RELEASE}.conf" echo } function get_freebsd() { # For future releases, use dvd1 iso files. local URL="" local DL_BASE="https://download.freebsd.org/ftp/releases/amd64/amd64/ISO-IMAGES" local VERSION="" case ${RELEASE} in 12_2|13_0) VERSION=${RELEASE//_/.};; *) echo "ERROR! FreeBSD ${RELEASE} is not a supported release." releases_freebsd exit 1 ;; esac URL="${DL_BASE}/${VERSION}/FreeBSD-${VERSION}-RELEASE-amd64-dvd1.iso" ISO="FreeBSD-${VERSION}-RELEASE-amd64-dvd1.iso" web_get ${URL} ${VM_PATH} make_vm_dir make_vm_config ${ISO} start_vm_info } function get_macos() { local CWD="" local MACRECOVERY="" case ${RELEASE} in high-sierra) BOARD_ID="Mac-7BA5B2D9E42DDD94" MLB="00000000000J80300";; mojave) BOARD_ID="Mac-7BA5B2DFE22DDD8C" MLB="00000000000KXPG00";; catalina) BOARD_ID="Mac-CFF7D910A743CAAF" MLB="00000000000PHCD00";; big-sur) BOARD_ID="Mac-E43C1C25D4880AD6" MLB="00000000000000000";; *) echo "ERROR! Unknown release: ${RELEASE}" releases_macos exit 1;; esac # Use a bundled macrecovery if possible CWD="$(dirname ${0})" if [ -x "${CWD}/macrecovery" ]; then MACRECOVERY="${CWD}/macrecovery" elif [ -x /usr/bin/macrecovery ]; then MACRECOVERY="/usr/bin/macrecovery" else web_get "https://raw.githubusercontent.com/acidanthera/OpenCorePkg/master/Utilities/macrecovery/macrecovery.py" "${HOME}/.quickemu" MACRECOVERY="python3 ${HOME}/.quickemu/macrecovery.py" sed -i 's/\/env python3/g' "${MACRECOVERY}" fi if [ -z "${MACRECOVERY}" ]; then echo "ERROR! Can not find a usable macrecovery.py." exit 1 fi make_vm_dir # Get firmware web_get "https://github.com/kholia/OSX-KVM/raw/master/OpenCore-Catalina/OpenCore.qcow2" "${VM_PATH}" web_get "https://github.com/kholia/OSX-KVM/raw/master/OVMF_CODE.fd" "${VM_PATH}" if [ ! -e "${VM_PATH}/OVMF_VARS-1024x768.fd" ]; then web_get "https://github.com/kholia/OSX-KVM/raw/master/OVMF_VARS-1024x768.fd" "${VM_PATH}" fi if [ ! -e "${VM_PATH}/RecoveryImage.chunklist" ]; then echo "Downloading ${RELEASE}..." ${MACRECOVERY} \ --board-id "${BOARD_ID}" \ --mlb "${MLB}" \ --basename RecoveryImage \ --outdir "${VM_PATH}" \ download fi if [ -e "${VM_PATH}/RecoveryImage.dmg" ] && [ ! -e "${VM_PATH}/RecoveryImage.img" ]; then echo "Converting RecoveryImage..." qemu-img convert "${VM_PATH}/RecoveryImage.dmg" -O raw "${VM_PATH}/RecoveryImage.img" fi make_vm_config RecoveryImage.img start_vm_info } function get_ubuntu() { local DEVEL="daily-live" local ISO="" local PROJECT="" local RELEASES="" local URL="" case ${OS} in kubuntu|lubuntu|ubuntu|ubuntu-budgie|ubuntu-mate|xubuntu) PROJECT="${OS}";; ubuntu-kylin) PROJECT="ubuntukylin";; ubuntu-studio) PROJECT="ubuntustudio" DEVEL="dvd";; *) echo "ERROR! ${OS} is not a recognised Ubuntu flavour." exit 1;; esac if [ "${RELEASE}" == "devel" ]; then URL="http://cdimage.ubuntu.com/${PROJECT}/${DEVEL}/current" elif [ "${PROJECT}" == "ubuntu" ]; then URL="http://releases.ubuntu.com/${RELEASE}" else URL="http://cdimage.ubuntu.com/${PROJECT}/releases/${RELEASE}/release" fi RELEASES=$(releases_ubuntu) if [[ "${RELEASES}" != *"${RELEASE}"* ]]; then echo "ERROR! ${RELEASE} is not a supported release." releases_ubuntu exit 1 fi make_vm_dir echo "Downloading SHA256SUMS..." web_get "${URL}/SHA256SUMS" "${VM_PATH}" ISO=$(grep 'desktop\|dvd' "${VM_PATH}/SHA256SUMS" | grep amd64 | cut -d' ' -f2 | sed 's|*||g') echo "Downloading "${URL}/${ISO}"..." if [ "${RELEASE}" == "devel" ]; then zsync_get "${URL}/${ISO}" "${VM_PATH}" "${OS}-${RELEASE}.iso" make_vm_config "${OS}-${RELEASE}.iso" else web_get "${URL}/${ISO}" "${VM_PATH}" echo "Checking SHA256SUMS..." cd "${VM_PATH}" if ! sha256sum --check SHA256SUMS --ignore-missing --status; then echo "ERROR! ${ISO} doesn't match ${VM_PATH}/SHA256SUMS. Try running 'quickget' again." exit 1 else echo "All good." fi cd .. make_vm_config "${ISO}" fi start_vm_info } # Adapted from https://gist.github.com/hongkongkiwi/15a5bf16437315df256c118c163607cb function get_windows() { case ${RELEASE} in 8|10|11) true;; *) echo "ERROR! Windows ${RELEASE} is not supported." releases_windows exit 1 ;; esac local ARCH="x64" local LANG_CODE="en" local LATEST_WINDOWS_VERSION="" local WINDOWS_NAME="" local VERSION_ID="" local EDITION_ID="" local LANGUAGE_ID="" local FILE_NAME="" local ARCH_ID="" local DOWNLOAD_INFO="" local DOWNLOAD_ID="" local DOWNLOAD_URL="" echo "Getting Windows ${RELEASE} URL..." WINDOWS_VERSIONS=$(wget -q -O- "https://tb.rg-adguard.net/php/get_version.php?type_id=1" | jq '.versions | sort_by(-(.version_id | tonumber))') LATEST_WINDOWS_VERSION=$(echo "${WINDOWS_VERSIONS}" | jq -c 'map(select(.name | contains("Windows '${RELEASE}'")))[0]') WINDOWS_NAME=$(echo "${LATEST_WINDOWS_VERSION}" | jq -r .name) VERSION_ID=$(echo "${LATEST_WINDOWS_VERSION}" | jq -r .version_id) case ${RELEASE} in 8) EDITION_ID=$(wget -q -O- "https://tb.rg-adguard.net/php/get_edition.php?version_id=${VERSION_ID}&lang=name_${LANG_CODE}" | jq -r '.editions[] | select(.name_'${LANG_CODE}'=="Windows 8.1 Pro + Core").edition_id');; 10|11) EDITION_ID=$(wget -q -O- "https://tb.rg-adguard.net/php/get_edition.php?version_id=${VERSION_ID}&lang=name_${LANG_CODE}" | jq -r '.editions[] | select(.name_'${LANG_CODE}'=="Windows '${RELEASE}'").edition_id');; esac LANGUAGE_ID=$(wget -q -O- "https://tb.rg-adguard.net/php/get_language.php?edition_id=${EDITION_ID}&lang=name_${LANG_CODE}" | jq -r '.languages[] | select(.name_'${LANG_CODE}'=="'"${LANG_NAME}"'").language_id') ARCH_INFO=$(wget -q -O- "https://tb.rg-adguard.net/php/get_arch.php?language_id=${LANGUAGE_ID}") FILE_NAME=$(echo "${ARCH_INFO}" | jq -r '.archs[] | select(.name | contains("'${ARCH}'")).name') ARCH_ID=$(echo "${ARCH_INFO}" | jq -r '.archs[] | select(.name | contains("'${ARCH}'")).arch_id') DOWNLOAD_INFO=$(wget -q -O- "https://tb.rg-adguard.net/dl.php?fileName=${ARCH_ID}&lang=en") DOWNLOAD_ID=$(echo "${DOWNLOAD_INFO}" | grep -oP '(?<=https:\/\/tb\.rg-adguard\.net/dl\.php\?go=)[0-9a-z]+') DOWNLOAD_URL="https://tb.rg-adguard.net/dl.php?go=${DOWNLOAD_ID}" make_vm_dir echo "Downloading ${WINDOWS_NAME}..." web_get "${DOWNLOAD_URL}" "${VM_PATH}" "${FILE_NAME}" echo "Downloading virtio-win.iso..." web_get "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso" "${VM_PATH}" if [ ! -e "${VM_PATH}/unattended.iso" ]; then case ${RELEASE} in 10|11) echo "Making unattended.iso" unattended_windows "${VM_PATH}/unattended/autounattend.xml" mkisofs -quiet -l -o "${VM_PATH}/unattended.iso" "${VM_PATH}/unattended/" ;; esac fi make_vm_config "${FILE_NAME}" "virtio-win.iso" start_vm_info } if [ -n "${1}" ]; then OS="${1,,}" else echo "ERROR! You must specify an OS:" os_support exit 1 fi if [ -n "${2}" ]; then RELEASE="${2,,}" else echo "ERROR! You must specify an OS release name." if [ "${OS}" == "freebsd" ]; then releases_freebsd elif [ "${OS}" == "macos" ]; then releases_macos elif [[ "${OS}" == *"ubuntu"* ]]; then releases_ubuntu elif [ "${OS}" == "windows" ]; then releases_windows fi exit 1 fi VM_PATH="${OS}-${RELEASE}" if [ "${OS}" == "macos" ]; then get_macos elif [[ "${OS}" == *"freebsd" ]]; then get_freebsd elif [[ "${OS}" == *"ubuntu"* ]]; then get_ubuntu elif [ "${OS}" == "windows" ]; then if [ -n "${3}" ]; then LANG_NAME="${3}" LANG_NAMES=$(languages_windows) if [[ "${LANG_NAMES}" != *"${LANG_NAME}"* ]]; then echo "ERROR! ${LANG_NAME} is not a supported language:" languages_windows exit 1 fi else LANG_NAME="English International" fi get_windows "${LANG_NAME}" else echo "ERROR! You must specify an OS:" os_support exit 1 fi