#!/usr/local/bin/cbsd
#v15.0.0
CBSDMODULE="bhyve"
CIXMYARG="jname"
CIXOPTARG="bootrom com1 com2 com3 com4 display header lpcslot_name mode select tpm"
MYDESC="Manage bhyve VM LPC devices: COM/TPM2/bootrom and so on"
ADDHELP="
${H3_COLOR}Description${N0_COLOR}:

Manage bhyve VM LPC devices: COM/TPM2/bootrom and so on.

If the TPM path begins with the '/dev/' prefix, it means PASSTHRU mode. 
If the 'swtpm' package is installed, you can set 'tpm=' as 'new' value for emulation.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}jname=${N0_COLOR}  - target VM.
 ${N2_COLOR}mode=${N0_COLOR}   - mode (list by default when no other arguments):
           * reset -   reset to default;
           * get   -   get values;
           * list  -   list of devices;

${H3_COLOR}Examples${N0_COLOR}:

  # cbsd blpc jname=vm1
  # cbsd blpc jname=vm1 tpm=new				# emulate via swtpm
  # cbsd blpc jname=vm1 tpm=/dev/tpm0			# passthru /dev/tpm*
  # cbsd blpc jname=vm1 mode=get lpcslot_name=com1
  # cbsd blpc jname=vm1 com1="tcp=127.0.0.1:9000"
  # cbsd blpc jname=vm1 com2="serial"
  # cbsd blpc jname=vm1 mode=reset

${H3_COLOR}See also${N0_COLOR}:

 cbsd blpc-tui --help
 cbsd bconfig --help
 cbsd bset --help
 cbsd bhyve-ppt --help

"

. ${subrdir}/nc.subr
. ${tools}
. ${strings}

select="lpcslot_value"		# by default, select PCI bus
device_name=

bootrom=
com1=
com2=
com3=
com4=
tpm=
obootrom=
ocom1=
ocom2=
ocom3=
ocom4=
otpm=
cixinit

. ${subrdir}/rcconf.subr
case "${emulator}" in
	bhyve|xen|qemu)
		true
		;;
	*)
		log_err 1 "${N1_COLOR}Not supported emulator: ${N2_COLOR}${jname}${N0_COLOR}"
		;;
esac

[ -z "${display}" ] && display="lpcslot_name,lpcslot_value"

#remove commas for loop action on header
mydisplay=$( echo ${display} | ${TR_CMD} ',' '  ' )

# upper for header
myheader=$( echo ${mydisplay} | ${TR_CMD} '[:lower:]' '[:upper:]' )

show_header()
{
	local _header="${H1_COLOR}${BOLD}${myheader}${N0_COLOR}"
	[ ${header} -ne 0 ] && ${ECHO} "${_header}"
}

# if $1 = "Unregister" then overwrite status to "Unregister"
populate_output_data()
{
	local _i= _val= src_size=

	_status=

	#populate values for in output string
	for _i in ${mydisplay}; do
		_val=
		eval _val=\$$_i
		[ -z "${_val}" ] && _val="-"
		if [ -z "${_status}" ]; then
			_status="${N0_COLOR}${_val}"
		else
			_status="${_status} ${_val}"
		fi
	done
}


# $1 - which file from. Eg: local
show_basesdata_from_sql()
{
	local _i=

	#   set sqlfile for ". rcconf" including
	if [ -n "${1}" ]; then
		sqlfile="$1"
	else
		sqlfile="local"
	fi

	_sql="SELECT lpcslot_name,lpcslot_value FROM lpc"

	OIFS="${IFS}"
	IFS="|"
	sqldelimer="|"

	cbsdsqlro ${sqlfile} ${_sql} | while read lpcslot_name lpcslot_value; do
		IFS="${OIFS}"
		populate_output_data
		printf "${N2_COLOR}"
		printf "${_status}"
		printf "${N0_COLOR}\n"
		IFS="|"
	done
	IFS="${OIFS}"
}

show_remote()
{
	show_header

	[ -z "${node}" ] && node=$( node mode=list header=0 allinfo=0 )

	for _n in ${node}; do
		nodename="${_n}"
		show_basesdata_from_sql "inv.${_n}"
	done
}

show_local()
{
	local _errcode= _status=

	show_header
	show_basesdata_from_sql ${jailsysdir}/${jname}/local.sqlite
}

show_lpc()
{
	if [ -n "${node}" ]; then
		show_remote
		exit
	fi

	show_local
}

#### MAIN
[ -z "${header}" ] && header=1
_args=0

# any oXXX params is set? When no mode set and no args = force to mode=list
for i in bootrom com1 com2 com3 com4 tpm; do
	eval _val=\$o$i
	[ -n "${_val}" ] && _args=$(( _args + 1 ))
done

[ ${_args} -eq 0 -a -z "${mode}" ] && mode=list

case "${mode}" in
	get)
		[ -z "${lpcslot_name}" ] && err 1 "${N2_COLOR}lpcslot_name= ${N1_COLOR} is mandatory${N0_COLOR}"
		_sql="SELECT ${select} FROM lpc WHERE lpcslot_name='${lpcslot_name}'"
		sqllistdelimer=" "
		cbsdsqlro ${jailsysdir}/${jname}/local.sqlite ${_sql}
		exit 0
		;;
	list)
		sqllistdelimer=" "
		show_lpc | ${COLUMN_CMD} -t
		exit 0
		;;
	reset)
		# truncate pcibus_run table
		#cbsdsqlrw ${jailsysdir}/${jname}/local.sqlite DELETE FROM pcibus
		${ECHO} "${N1_COLOR}Reset lpc table for: ${N2_COLOR}${jname}${N0_COLOR}"
		exit 0
		;;
esac

# SET MODE
for i in bootrom com1 com2 com3 com4 tpm; do
	eval _val=\$o$i
	if [ -n "${_val}" ]; then
		${ECHO} "${N0_COLOR}${CIX_APP}: set ${i}: ${N2_COLOR}${_val}${N0_COLOR}"
		cbsdsqlrw "${jailsysdir}/${jname}/local.sqlite" "UPDATE lpc SET lpcslot_value='${_val}' WHERE lpcslot_name='${i}'"
		case "${_val}" in
			tpm)
				# dup to global
				cbsdsqlrw "${jailsysdir}/${jname}/local.sqlite" "UPDATE lpc SET lpcslot_value='${_val}' WHERE lpcslot_name='${i}'"
				;;
		esac
	fi
done

exit 0
