#!/bin/bash
ACTION='run'    # what to do
IMG='none'      # name of image to boot
QCOW2='none'    # name for qcow2 image to install
SIZE='12'       # size for qcow2 image to install
RAM='auto'      # ram for machine
QEMUADD=''      # additional parameters for qemu
EFI_FIRMWARE="-bios /usr/share/OVMF/OVMF_CODE.fd"
PREFIX='_qemoo' # prefix for generating qcow2 file name
SHARE='./'      # share dir

### initialized empty, not for config
EFI=''
INSTALL=''
###

[ -f '/ect/qemoo.cfg' ] && . /etc/qemoo.cfg
[ -f './qemoo.cfg' ] && . ./qemoo.cfg

while [ -n "$1" ]
do
	case "$1" in
	"-i" | "--install" ) ACTION='install' ;; # install from ISO to a qcow2 instead sipmle run
	"-r" | "--run"     ) ACTION='run' ;; # run (default)
	"-s" | "--size"    ) shift; SIZE=$1 ;; # <par> size for new qcow2 (only with --install)
	"-q" | "--qcow2"   ) shift; QCOW2="$1" ;; # <par> name for new or existing qcow2 (only with --install)
	"-m" | "--mem"     ) shift; RAM=$1 ;; # <par> size or RAM to guest machine
	"-L" | "--ll"   | "--lowlevel" ) REDIRUSB='yes' ;; # lowlevel redirect USB drive to guest machine, useful for tokens, modems, etc.
	"-e" | "--efi"  | "--uefi"     ) EFI="$EFI_FIRMWARE" ;; # efi instead legacy bios
	"-l" | "--loop" | "--losetup"  ) LOSETUP='yes' ;; # use ISO and IMG files attaching as loop device
	"-S" | "--show-cmdline"        ) SHOW='yes' ;; # do not run qemu, show qemu cmdline only
	"-h" | "--help"    ) # this help
	echo "Usage: $0 /path/to/image <parameters>"
	cat $0 |sed -n '/).*#.*/s/).*#/ - /p' |grep -v cat
	exit;;
	"--" )  shift ; QEMUADD+=" $@" # <par> additional parameters for qemu in the end of cmdline
			break ;;
	*) IMG=$1 ;;
	esac
	shift
done

run() {
	cmdline="$@"
	if [ "$SHOW" ] ; then
		echo $cmdline
	else
		$cmdline
	fi
}

checkImg(){
	if [ "$IMG" == 'none' ] ; then
		echo "No image name" 1>&2
		echo 'error'
		return
	elif ! [ -e $IMG ] ; then
		echo "$IMG - not exists" 1>&2
		echo 'error'
		return
	fi
	if echo "$IMG" |grep -q '^/dev/\(cdrom\|sr[0-9]\+\)'; then
		echo "iso"
		return 0
	elif echo "$IMG" |grep -q '^/dev/.\+'; then
		if [ -b "$IMG" ] ; then
			echo "blockdev"
			return 0
		else
			echo "$IMG - is not block device" 1>&2
			echo 'error'
			exit ${LINENO}
		fi
	elif  file "$IMG" | grep -q "ISO 9660"; then
		echo "iso"
		return 0
	else
		echo "virt"
		return 0
	fi
}

nameGen(){
	local NAME LAST
	LAST=$(ls -1 ./ |grep $PREFIX |sort -V |tail -n1)
	NAME=$(basename $IMG)
	if [ -n "$LAST" ] ; then
		n=$(echo $LAST |sed 's/'$PREFIX'//' |sed 's/_...\.qcow2//')
		expr $n + 1 >/dev/null 2>&1 && suffix=$(($n + 1))
	else
		suffix=1
	fi
echo ${PREFIX}${suffix}_${NAME:0:3}.qcow2
}

mkQcow2(){
	[ "$QCOW2" == 'none' ] && QCOW2=$(nameGen)
    if [ -f "$QCOW2" ] ; then
		echo "$QCOW2 already exists" 1>&2
		echo $QCOW2
		return 0
	fi
	if run qemu-img create -f qcow2 "${QCOW2}" ${SIZE}G 1>&2 ; then
		echo "$QCOW2"
	else
		echo 'error'
	fi
}

checkRam() {
	HOSTRAM=$(expr $(cat /proc/meminfo |grep MemTotal |awk '{print $2}') / 1000)
	if [ "$RAM" == 'auto' ] ; then
		RAM=$(( $HOSTRAM / 2 ))
		[ "$RAM" -gt 4272 ] && RAM='4272' # (free -g: total 4G)
		echo "$RAM"
	else
		if expr $RAM + 1 >/dev/null 2>&1 ; then
			if [ "$RAM" -lt "$HOSTRAM" ] ; then
				echo $RAM
			else
				echo "RAM size: $RAM greater then host RAM" 1>&2
				echo 'error'
			fi
		else
			echo "RAM size: $RAM - is not digit" 1>&2
			echo 'error'
		fi
	fi
}

checkUSB(){
	DEVNAME="$(basename $IMG)"
	source <(udevadm info -q property /dev/$DEVNAME |grep 'ID_' |sed 's/=\(.*\)/="\1"/')
	if [ "$ID_BUS" = "usb" ]; then
		echo "-usb -device usb-host,vendorid=0x${ID_VENDOR_ID},productid=0x${ID_MODEL_ID}"
	fi
}

QEMU="qemu-system-$(arch)"
if ! command -V "$QEMU" >/dev/null; then
	echo "$QEMU not found"
	exit ${LINENO}
fi

IMGFORMAT="$(qemu-img info $IMG |grep 'format:' |cut -d' ' -f3)"
if [ "$LOSETUP" -a "$IMGFORMAT" = "raw" ] && echo "$IMG" |grep -qv '^/dev/'; then
	LOOPDEV="$(losetup -f)"
	losetup $LOOPDEV $IMG && { IMG="$LOOPDEV"; trap "losetup -d $LOOPDEV" EXIT; } || exit 1
fi

type=$(checkImg)
[ "$type" == 'error' ] && exit ${LINENO}

if [ "$ACTION" == 'install' ] ; then
	qImg=$(mkQcow2)
	[ "$qImg" == 'error' ] && exit ${LINENO}
fi

vRam=$(checkRam)
[ "$vRam" == 'error' ] && exit ${LINENO}

MAC="0a:$({ LC_MESSAGES=en fdisk -l $IMG 2>/dev/null |grep ident || stat -c%W $IMG; } |
	md5sum |sed 's/\(..\)/\1:/g' |cut -c 1-14)"

DRIVEPARS="file=$IMG,format=$IMGFORMAT,cache=none"

COMMON="$QEMU $EFI \
	-cpu host \
	-machine q35,accel=kvm:tcg \
	-name $(basename $IMG) \
	-nic mac=$MAC \
	-m ${vRam}M \
	-rtc base=localtime \
	-virtfs local,path=$SHARE,mount_tag=hostdir,security_model=mapped,id=hostdir
"

[ "$REDIRUSB" ] && usbDev="$(checkUSB)"

[ "$ACTION" == 'install' ] && INSTALL="-drive file=$qImg,cache=none"

case $type in
	'virt' )
		echo "Virtual machine image: $IMG"
		cmdline="
		-boot c \
		-drive $DRIVEPARS"
		;;
	'blockdev')
		echo "Block device: $IMG"
		cmdline="
		-boot c \
		${usbDev:--drive $DRIVEPARS}"
		;;
	'iso')
		echo "ISO: $IMG"
		cmdline="
		-boot d \
		-drive $DRIVEPARS,media=cdrom"
		;;
	*)
		echo "unknown type: $type"
		exit ${LINENO}
esac

echo "Host share:
	$(realpath $SHARE)
Linux guest mount command example:
	mkdir /mnt/hostdir
	mount -t 9p -o trans=virtio,msize=100000000 hostdir /mnt/hostdir"

run $COMMON  $cmdline  $INSTALL  $QEMUADD

