#!/bin/sh

# Set ZFS properties
__zfs_set() {
	local name="$2"
	if [ -z "$3" ]; then
		printf "missing argument\nusage:\n"
		printf "\tset <name> <property=value> ...\n"
		exit 1
	fi
	if ! __guest_exist $name; then
		echo "Guest $name doesn't exist!"
		return 1
	fi
	local pool="$(zfs list -H -t volume | cut -d '/' -f-3 | grep iohyve/$name | cut -d '/' -f 1 | head -n1)"
	shift 2
	for arg in "$@"; do
		local prop="$(echo $arg | cut -d '=' -f1)"
		local val="$(echo $arg | cut -d '=' -f2-)"
		if [ $prop = "bargs" ]; then
			local sval="$(echo $val | cut -d '"' -f2 | sed -e 's/ /_/g')"
			echo "Setting $name $prop=$val..."
			zfs set iohyve:$prop=$sval $pool/iohyve/$name
		elif [ $prop = "description" ]; then
			local sval="$(echo $val | cut -d '"' -f2)"
			echo "Setting $name $prop=$val..."
			zfs set "iohyve:$prop=$sval" $pool/iohyve/$name
		else
			echo "Setting $name $prop=$val..."
			zfs set iohyve:$prop=$val $pool/iohyve/$name
		fi
	done
}

# Get ZFS props
__zfs_get() {
	local name="$2"
	local prop="$3"
	if [ -z "$prop" ]; then
		printf "missing argument\nusage:\n"
		printf "\tget <name> <prop>\n"
		exit 1
	fi
	local pool="$(zfs list -H -t volume | cut -d '/' -f-3 | grep iohyve/$name | cut -d '/' -f 1 | head -n1)"
	echo "Getting $name prop $prop..."
	zfs get -H -o value iohyve:$prop $pool/iohyve/$name
}

# Remove a property
__zfs_rmprop() {
	local flagone="$2"
	local flagtwo="$3"
	local flagthree="$4"
	if [ $flagone = "-f" ]; then
		if [ -z "$flagthree" ]; then
			printf "missing argument\nusage:\n"
			printf "\trmpci [-f] <name> <pcidev:N>\n"
			exit 1
		fi
		echo "Removing $flagthree from $flagtwo"
		echo "I hope you picked the right property. Removing the wrong one can lead to bad things."
		local pool="$(zfs list -H -t volume | cut -d '/' -f-3 | grep $flagtwo | cut -d '/' -f 1 | head -n1)"
		zfs inherit  -r iohyve:$flagthree $pool/iohyve/$flagtwo
	else
		if [ -z "$flagtwo" ]; then
			printf "missing argument\nusage:\n"
			printf "\trmpci [-f] <name> <pcidev:N>\n"
			exit 1
		fi
		local pool="$(zfs list -H -t volume | cut -d '/' -f-3 | grep $flagone | cut -d '/' -f 1 | head -n1)"
		echo "Warning: Deleting the wrong property can lead to bad things."
		read -p "Are you sure you want to remove $flagtwo [Y/N]? " an </dev/tty
		case "$an" in
			y|Y) zfs inherit  -r iohyve:$flagtwo $pool/iohyve/$flagone
			;;
			*) echo "Not removed..."
			;;
		esac
	fi
}

# Get all ZFS props
__zfs_getall() {
	local name="$2"
	if [ -z "$name" ]; then
		printf "missing argument\nusage:\n"
		printf "\tgetall <name>\n"
		exit 1
	fi
	local pool="$(zfs list -H -t volume | cut -d '/' -f-4 | grep iohyve/$name | grep disk0 | cut -d '/' -f 1 | head -n1)"
	echo "Getting $name iohyve properties..."
	zfs get -o property,value all $pool/iohyve/$name | grep iohyve: | sort | sed -e 's/iohyve://g'
}

# Snapshot a guest
__zfs_snapguest() {
	local fullsnap="$2"
	local name="$(echo $fullsnap | cut -d '@' -f1)"
	if [ -z "$name" ] || [ -z "$(echo $fullsnap | grep '@')" ]; then
		printf "missing argument\nusage:\n"
		printf "\tsnap <name>@<snap>\n"
		exit 1
	fi
	local pool="$(zfs list -H -t volume | cut -d '/' -f-4 | grep iohyve/$name | grep disk0 | cut -d '/' -f 1 | head -n1)"
	echo "Taking snapshot $fullsnap"
	# Check if guest exists
	if [ -d /iohyve/$pool/$name ] || [ -d /iohyve/$name ]; then
		zfs snap -r $pool/iohyve/$fullsnap
	else
		echo "Not a valid guest name"
	fi
}

# Rollback guest
__zfs_rollguest() {
	local fullsnap="$2"
	local name="$(echo $fullsnap | cut -d '@' -f1)"
	local pool="$(zfs list -H -t volume | cut -d '/' -f-4 | grep iohyve/$name | grep disk0 | cut -d '/' -f 1 | head -n1)"
	local snap="$(echo $fullsnap | cut -d '@' -f2)"
	if [ -z "$snap" ] || [ -z "$(echo $fullsnap | grep '@')" ]; then
		printf "missing argument\nusage:\n"
		printf "\troll <name>@<snap>\n"
		exit 1
	fi
	local disklist="$(zfs list -H | cut -d '/' -f-4 | grep iohyve/$name | grep disk | cut -f1 | cut -d '/' -f4-)"
	# Check if guest exists
	echo "Rolling back to $fullsnap"
	if [ -d /iohyve/$pool/$name ] || [ -d /iohyve/$name ]; then
		# Check to make sure guest isn't running
		local running=$(pgrep -fx "bhyve: ioh-$name")
		if [ -z "$running" ]; then
			zfs rollback -rR $pool/iohyve/$fullsnap
			for disk in $disklist ; do
				zfs rollback -rR $pool/iohyve/$name/$disk@$snap
			done
		else
			echo "Please stop the guest first"
		fi
	else
		echo "Not a valid guest name"
	fi
}

# Remove a snap
__zfs_rmsnap() {
	local flagone="$2"
	local flagtwo="$3"
	if [ $flagone = "-f" ]; then
		if [ -z "$flagtwo" ]; then
			printf "missing argument\nusage:\n"
			printf "\trmsnap [-f] <name>@<snapname>\n"
			exit 1
		fi
		echo "Removing snapshot $flagtwo"
		echo "I hope it was a snapshot and not a guest."
		local pool="$(zfs list -t snapshot | cut -d '/' -f-3 | grep "$flagtwo" | head -n1 | cut -f1 -d/)"
		zfs destroy -r $pool/iohyve/$flagtwo
	else
		local pool="$(zfs list -t snapshot | cut -d '/' -f-3 | grep "$flagone" | head -n1 | cut -f1 -d/)"
		echo "Warning: if you supply a guestname and not a guestname@snapname, you will destroy the guest."
		read -p "Are you sure you want to remove $flagone [Y/N]? " an </dev/tty
		case "$an" in
			y|Y) zfs destroy -r $pool/iohyve/$flagone
			;;
			*) echo "Not removed..."
			;;
		esac
	fi
}

# Clone a guest
__zfs_cloneguest() {
	local flag="$2"
	local name="$2"
	local cname="$3"

	if [ "$flag" == "-r" ]; then
		name="$3"
		cname="$4"
	fi

	if [ -z "$cname" ]; then
		printf "missing argument\nusage:\n"
		printf "\tclone <name> <clonename>\n"
		exit 1
	fi

	local description="$(date | sed -e 's/ /_/g')"
	local pool="$(zfs list -H -t volume | cut -d '/' -f-4 | grep iohyve/$name | grep disk0 | cut -d '/' -f 1 | head -n1)"
	# Check if guest exists
	echo "Cloning $name to $cname"
	if [ -d /iohyve/$pool/$name ] || [ -d /iohyve/$name ]; then
		# Take snapshot
		zfs snap -r $pool/iohyve/$name@$cname
		# zfs send that snap and desendants then receive to cname
		zfs send -R $pool/iohyve/$name@$cname | \
		zfs recv $pool/iohyve/$cname
		# clean up
		zfs destroy -rR $pool/iohyve/$name@$cname
		zfs destroy -rR $pool/iohyve/$cname@$cname
		# rename the guest
		zfs set iohyve:name=$cname $pool/iohyve/$cname
		zfs set iohyve:description=$description $pool/iohyve/$cname
		# change con and tap properties to next available if -r is specified
		if [ "$flag" == "-r" ]; then
			local taporig="$(zfs get -H -o value iohyve:tap $pool/iohyve/$name)"
			local tapcloned="$(__tap_cloned $taporig)"
			local conlast="$(__console_last)"

			zfs set iohyve:tap=$tapcloned $pool/iohyve/$cname
			zfs set iohyve:con=nmdm$conlast $pool/iohyve/$cname
		fi
	else
		echo "Not a valid guest name"
	fi
}

# Export Guest
__zfs_exportguest() {
	local name="$2"
	if [ -z "$name" ]; then
		printf "missing argument\nusage:\n"
		printf "\texport <name>\n"
		exit 1
	fi
	local pool="$(zfs list -H -t volume | cut -d '/' -f-4 | grep $name | grep disk0 | cut -d '/' -f 1 | head -n1)"
	local disklist="$(zfs list -H | cut -d '/' -f-4 | grep iohyve | grep $name | grep disk | \
				cut -f1 | cut -d '/' -f4-)"
	# Check if guest exists
	echo "Exporting $name. Note this may take some time depending on the size."
	if [ -d /iohyve/$pool/$name ] || [ -d /iohyve/$name ]; then
		# Check to make sure guest isn't running
		local running=$(pgrep -fx "bhyve: ioh-$name")
		if [ -z "$running" ]; then
			# Create /tmp/iohyve/$name
			echo "Creating temp directory..."
			mkdir -p /tmp/iohyve/$name
			# Export Properties to file
			echo "Exporting properties..."
			zfs get -H -o property,value all $pool/iohyve/$name | grep iohyve: | sort | \
				sed -e 's/iohyve://g' | sed -e 's/	/=/g' > /tmp/iohyve/$name/properties.ucl
			# Write disks to file
			echo "Exporting disks..."
			for disk in $disklist ; do
				dd if=/dev/zvol/$pool/iohyve/$name/$disk of=/tmp/iohyve/$name/${disk}.img bs=1M
			done
			# Compress and add to archive
			echo "Compressing to archive..."
			tar -czf /iohyve/$name/$name.tar.gz -C /tmp/iohyve/$name/ .
			# Remove /tmp/iohyve/
			echo "Removing temp directory..."
			rm -fr /tmp/iohyve
		else
			echo "Please stop the guest first"
		fi
	else
		echo "Not a valid guest name"
	fi
}

# List all the snapshots
__zfs_snaplist() {
	zfs list -H -t snap | cut -d '/' -f-3 | grep iohyve | grep '@' | grep -v disk | cut -f1 | cut -d '/' -f3
}

# Get PCI device config from zfs
__zfs_get_pcidev_conf() {
	local pool="$1"
	local oldifs=$IFS
	#local pci
	IFS=$'\n'
	# only display results of "filesystems" skipping properties on independent snapshots/volumes (many if autosnap enabled)
	for pcidev in $(zfs get -H -o property,value -t filesystem all $pool | grep iohyve:pcidev: | sort )
	do
		echo $pcidev | cut -f2-
	done
	IFS=$oldifs
}
