#!/bin/sh

# Setup iohyve
__setup() {
	shift 1
	local args="$@"
	local poolval
	local kmodval
	local netval

	# Exit with help output if setup has no arguments
	if [ -z "$@" ]; then
		echo "Please specify setup parameters."
		echo "Usage: 'iohyve setup <pool=poolname> [kmod=0|1] [net=iface]'"
		echo "See man page for details."
		exit 1
	fi
	for arg in $args; do
		local prop="$(echo $arg | cut -d '=' -f1)"
		local val="$(echo $arg | cut -d '=' -f2)"
		if [ $prop = "pool" ]; then
			poolval=$val
		elif [ $prop = "kmod" ]; then
			kmodval=$val
		elif [ $prop = "net" ]; then
			netval=$val
		fi

	done

#	if [ -n "$( grep 'POPCNT' /var/run/dmesg.boot )" -o -n "$( grep 'POPCNT' /var/log/dmesg )" ]; then
#		if [ -n "$( grep 'CPU:' /var/run/dmesg.boot | grep 'Intel' )" -o -n "$( grep 'CPU:' /var/log/dmesg | grep 'Intel' )" ] && \
#			 [ -z "$( grep 'VT-x:' /var/run/dmesg.boot | grep 'UG' )" -o -z "$( grep 'VT-x:' /var/log/dmesg | grep 'UG' )" ]; then
#			echo "Your CPU does not seem to fully support bhyve. Missing UG feature on Intel CPU, please upgrade to 5600 series."
#			echo "You may only be able to boot one bhyve guest on your machine at a time."
#			echo "Other restrictions may apply."
#		fi
#	else
#		echo "Your CPU does not seem to support bhyve."
#		echo "For AMD CPUs this means RVI. For Intel CPUs this means EPT."
#		echo "This may not end well for you."
#		echo "Other restrictions may apply."
#	fi

	# Run commands in correct order, so that the kernel modules are loaded
	# before the network is setup
	if [ -n "$poolval" ]; then
		__setup_pool $poolval
	fi
	if [ -n "$kmodval" ]; then
		__load_kernel_modules $kmodval
	fi
	if [ -n "$netval" ]; then
		__setup_network $netval
	fi
}

__setup_pool() {
	local pool="$1"
	zpool status $pool > /dev/null
	local poolstatus="$?"
	if [ "$poolstatus" -gt 0 ]; then
		echo "There are errors with the pool or pool name."
		echo "Please check the zpool status"
		exit 1
	fi
	if ! zfs list ${pool}/iohyve > /dev/null 2>&1; then
		echo "Setting up iohyve pool..."
		zfs create $pool/iohyve
		# iohyve is already setup on a pool
		if [ -d /iohyve/ISO ]; then
			echo "Secondary pool set up..."
			zfs set mountpoint="/iohyve/$pool" $pool/iohyve
			# iohyve is not set up yet
		else
			zfs set mountpoint="/iohyve" $pool/iohyve
			zfs create $pool/iohyve/ISO
			zfs create $pool/iohyve/Firmware
		fi
	else
		echo "iohyve already exists on $pool"
	fi
	# Checks to see if on FreeNAS
	# The web UI references this file to display the version
	if [ -e /etc/version ]; then
		local OS=$( cat /etc/version | cut -d - -f1 )
		if [ "$OS" = "FreeNAS" ]; then
			__setup_freenas $val
		fi
	fi
}

__setup_freenas() {
	local val=$1
	echo "On FreeNAS installation."
	echo "Checking for symbolic link to /iohyve from /mnt/iohyve..."
	if [ -d /mnt/iohyve ]; then
		if [ ! -e /iohyve ]; then
			ln -s /mnt/iohyve /iohyve
			if [ -L /iohyve ]; then
				echo "Symbolic link to /iohyve from /mnt/iohyve successfully created."
			else
				echo "Failed to create symbolic link."
				echo "Please manually do so by running the following as root:"
				echo "# ln -s /mnt/iohyve /iohyve"
			fi
		elif [ -L /iohyve ]; then
			echo "Symbolic link to /iohyve already exists."
		fi
	elif [ "$val" = "freenas-boot" ] && [ -d /iohyve ]; then
		echo "Symbolic link not needed. /iohyve exists."
		echo "iohyve is installed on the freenas-boot pool."
		echo "This is not recommended configuration."
	else
		echo "iohyve does not seem to be setup."
	fi
}

__load_kernel_modules() {
	local val=$1
	if [ $val = "1" ]; then
		echo "Loading kernel modules..."
		local modulelist
		if ! $(kldstat -q -m vmm); then
			modulelist="$modulelist vmm"
		fi
		if ! $(kldstat -q -m nmdm); then
			modulelist="$modulelist nmdm"
		fi
		if ! $(kldstat -q -m if_bridge); then
			modulelist="$modulelist if_bridge"
		fi
		if ! $(kldstat -q -m if_tap); then
			modulelist="$modulelist if_tap"
		fi
		# Load all modules together
		if [ "$modulelist" ]; then
			kldload $modulelist
		fi
	elif [ $val = "0" ]; then
		echo "Unloading kernel modules..."
		local modulelist
		if $(kldstat -q -m vmm); then
			modulelist="$modulelist vmm"
		fi
		if $(kldstat -q -m nmdm); then
			modulelist="$modulelist nmdm"
		fi
		if $(kldstat -q -m if_bridge); then
			modulelist="$modulelist if_bridge"
		fi
		if $(kldstat -q -m if_tap); then
			modulelist="$modulelist if_tap"
		fi
		# Unload all modules together
		if [ "$modulelist" ]; then
			kldunload $modulelist
		fi
	else
		echo "Improper syntax"
		echo "kmod=1 to load modules"
		echo "kmod=0 to unload modules"
	fi
}

__setup_bridge() {
	local iface=$1
	local bridgeif=""
	local ifaceexist=$('ifconfig' -l | tr ' ' '\n' | grep "$iface")
	if [ -n "$ifaceexist" ]; then
		local allbridges=$('ifconfig' -l | tr ' ' '\n' | grep "bridge" | sort -V)
		local lastbridge=$(echo $allbridges | tr ' ' '\n' | tail -n1 | cut -c7- )

		for bridge in $allbridges; do
			local bridgetest=$('ifconfig' $bridge | grep "member: $iface")
			if [ -n "$bridgetest" ]; then
				bridgeif=$bridge
			fi
		done

		if [ -z "$bridgeif" ]; then
			local nextbridge='0'
			if [ -n "$lastbridge" ]; then
				nextbridge="$(expr $lastbridge + 1)"
			fi
			bridgeif="bridge$nextbridge"

			ifconfig $bridgeif create descr "iohyve-bridge-$iface"
			ifconfig $bridgeif addm $iface
			ifconfig $bridgeif up
		fi
	fi

	echo $bridgeif
}

__setup_network() {
	local iface=$1
	local bridgeif="$(__setup_bridge $iface)"
	if [ -z "$bridgeif" ]; then
		echo "Setting up bridge with \"$iface\" failed!"
		return 1
	else
		echo "bridge \"$bridgeif\" is already enabled on this machine..."
		local sysctlexist
		if ! sysctlexist="$(sysctl -n net.link.tap.up_on_open 2> /dev/null)"; then
			echo "cannot set 'net.link.tap.up_on_open': is if_tap loaded?"
			return 1
		fi

		if [ $sysctlexist = "0" ]; then
			echo "Setting up correct sysctl value..."
			sysctl net.link.tap.up_on_open=1
		else
			echo "sysctl already setup properly as well..."
		fi
	fi
}
