#!/bin/sh set -o errexit # Helper script for running FreeBSD under bhyve # Downloads images/ISOs from FreeBSD master site # Maps in usb devices as desired to guest # Global constants dl_uri="https://download.freebsd.org/releases/" work_dir="." cpus="4" memory="4096M" # -E makes UEFI mode active in vmrun.sh bios="-E" usage() { echo "Usage:" echo " $0 [-r ] [-u ]" echo " [-t ]" echo "" echo " -r will select the latest BETA/ALPHA/RELEASE version available for download" echo " -t will select a VM_IMAGE (Default) or ISO (Install from scratch) for download" echo " -u will optionally enable passthrough of specific USB device from HOST to GUEST" exit 1 } # If variable not defined, define default. r="RELEASE" t="VM" while getopts ":a:r:u:t:" opt; do case "${opt}" in r) r=${OPTARG} # If it does not match BETA or ALPHA set to RELEASE [ ${r} = "BETA" -o ${r} = "ALPHA" ] || r="RELEASE" ;; u) u=${OPTARG} ;; t) t=${OPTARG} # Only support VM and ISO at the moment. [ ${t} = "VM" -o ${t} = "ISO" ] || t="VM" ;; *) usage ;; esac done shift $((OPTIND-1)) # Handle the architecture specific variables and arguments arch="$(sysctl -n hw.machine_arch)" archvariant="${arch}" kldload -n vmm pkg info edk2-bhyve || pkg install -y edk2-bhyve validate-sha512() { set +o errexit [ -z "${1}" -o ! -s ${1} ] && echo "No file ${1} for hash verification" && exit 1 echo "Validating SHA512 CHECKSUM..." # We are cheating a bit and just using file globs so we don't need to pass in exact CHECKSUM filename expect_hash=$(grep ${1} CHECKSUM.SHA512* | cut -d "=" -f 2 | tr -d ' ') #echo "expect_hash: ${expect_hash}" actual_hash=$(sha512sum --quiet ${1} | tr -d ' ') #echo "actual_hash: ${actual_hash}" if [ "${expect_hash}" != "${actual_hash}" ] ; then printf "Failure validating hash on ${1}. \nExpect: ${expect_hash} \nActual: ${actual_hash}\n" exit 1 fi set -o errexit } fetch-image() { latest_version=$(curl -s ${dl_uri}VM-IMAGES/ \ | grep -E -o -e "[0-9.]{3}[0-9]{1}-${r}[0-9]*/" | uniq | sort -gr | head -1 | tr -d '/') image_file="FreeBSD-${latest_version}-${archvariant}-ufs.raw" echo "Getting ready to fetch and/or start ${image_file}" if [ ! -s ${image_file} ] ; then fetch "${dl_uri}VM-IMAGES/${latest_version}/${arch}/Latest/${image_file}.xz" "${dl_uri}VM-IMAGES/${latest_version}/${arch}/Latest/CHECKSUM.SHA512" validate-sha512 ${image_file}.xz unxz ${image_file}.xz qemu-img resize ${image_file} +45G fi } fetch-iso() { toplevel_version=$(curl -s ${dl_uri}VM-IMAGES/ \ | grep -E -o -e "[0-9.]{3}[0-9]{1}-${r}[0-9]*/" | uniq | sort -gr | \ head -1 | tr -d '/' | sed s/-${r}[0-9]*//1) #echo "toplevel_version: ${toplevel_version}" latest_version=$(curl -s ${dl_uri}ISO-IMAGES/${toplevel_version}/ \ | grep -E -o -e "[0-9.]{3}[0-9]{1}-${r}[0-9]*" | uniq | sort -gr | head -1 | tr -d '/') #echo "latest_version: ${latest_version}" iso_file="FreeBSD-${latest_version}-${archvariant}-bootonly.iso" echo "Getting ready to fetch and/or start ${iso_file}" iso_boot_cli="-i -I ${iso_file}" image_file="FreeBSD-${latest_version}-${archvariant}-ufs.raw" iso_dl_uri="${dl_uri}ISO-IMAGES/${toplevel_version}/${iso_file}" checksum_dl_uri="${dl_uri}ISO-IMAGES/${toplevel_version}/CHECKSUM.SHA512-FreeBSD-${latest_version}-${archvariant}" if [ ! -s ${iso_file} ] ; then fetch "${iso_dl_uri}.xz" "${checksum_dl_uri}" validate-sha512 ${iso_file}.xz unxz ${iso_file}.xz fi if [ ! -s ${image_file} ] ; then truncate -s 45G ${image_file} else read -p "You selected ISO Install with an existing disk image ${image_file}. Do you wish to remove the existing file and recreate a blank disk file ? (y/n): " overwrite if [ "${overwrite}" = "y" -o "${overwrite}" = "Y" ] ; then rm ${image_file} truncate -s 45G ${image_file} fi fi } setup-usb-passthrough() { echo "Attempting to passthrough usb host device based on query string: ${u}" usb_map_count=$(usbconfig | grep -cie ${u}) [ ${usb_map_count} -ne 1 ] && \ echo "Total devices matched: ${usb_map_count} is not equal to 1, please refine." && \ usbconfig && exit 1 usb_map=$(usbconfig | grep -ie ${u} | grep -E -o -e "[0-9]+\.[0-9]+") #echo "usb_map: ${usb_map}" usb_map_bus=$(echo ${usb_map} | grep -E -o -e "^[0-9]+") usb_map_addr=$(echo ${usb_map} | grep -E -o -e "[0-9]+$") usb_qemu_cli="-device usb-host,hostbus=${usb_map_bus},hostaddr=${usb_map_addr},id=${u}" echo "Mapping usb device $(usbconfig | grep -ie ${u}) into the guest." #echo "usb_qemu_cli = ${usb_qemu_cli}" echo -n "In qemu monitor, you can inspect attached usb guest devices with \"info usb\" " echo "command, or delete the usb device mapping with \"device_del ${u}\"" } [ ${t} = "VM" ] && fetch-image [ ${t} = "ISO" ] && fetch-iso [ ! -z "${u}" ] && setup-usb-passthrough # Safety check. set +o errexit ps -aux | grep -v -e grep -e start_bhyve | grep -cq bhyve && \ echo "Bhyve is already running. Shutdown the guest, then retry." && exit 1 # Cleanup tap0 interfaces that are not in use anymore. ifconfig tap0 2>/dev/null | grep -cq -e "Opened by PID" || ifconfig tap0 destroy 2>/dev/null || true set -o errexit echo "Starting Bhyve using vmrun.sh in background..." vmrun.sh -m ${memory} -c ${cpus} \ ${bios} \ ${iso_boot_cli} \ -d ${work_dir}/${image_file} \ -t tap0 \ ${image_file} echo "Connect to guest console (telnet localhost 4444), or qemu monitor (telnet localhost 4445)" if [ ${t} = "ISO" ] ; then #telnet localhost 4444 fi