#!/usr/local/bin/cbsd
#v11.1.4
CIXARG="jname"
CBSDMODULE="bhyve"

. ${subrdir}/nc.subr
. ${distsharedir}/bhyve.conf

#concat for bhyve arg
JARG="${MYCOL} nice vm_pid soundhw soundhw_play soundhw_rec nic_ratelimit dsk_iops_limit dsk_mbps_limit gid com1 com2 com3 com4"
CIXOPTARG="jconf ${JARG} jname quiet"

MYDESC="Modify parameters for bhyve domain"
ADDHELP="
${H3_COLOR}Description${N0_COLOR}:

You can change VM options using arguments or config file.
Some parameters can be applied while the VM is running,
but most will require a VM restart.

You can change multiple parameters at one time separated by space.

For interactive (dialog(1)-based) edit, please use 'cbsd bconfig' instead.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}jconf=${N0_COLOR}     - <path_to_file>, load and set settings from jconf
 ${N2_COLOR}mode=${N0_COLOR}      - set 'force' for modification on the running bhyve
 ${N2_COLOR}vm_pid=${N0_COLOR}    - when 'auto', force to update pid from process list
 ${N2_COLOR}quiet=${N0_COLOR}     - 0,1: be quiet, dont output verbose message.

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd bset jname=myvmm vm_ram="4g"
 # cbsd bset jname='*' cpus=8 hdd_boot_firmware=refind

${H3_COLOR}See also${N0_COLOR}:

  cbsd bget --help
  cbsd bconfig --help

"

. ${tools}
. ${strings}
. ${tools}
quiet=0
oquiet=0
cixinit

emulator="bhyve"	# for jname_is_multiple
jname_is_multiple

if [ -n "${jail_list}" ]; then
	new_arg=

	for i in ${CIX_OTHER_ARGS}; do
		capture _is_jname substr --pos=0 --len=5 --str="${i}"
		[ "${_is_jname}" = "jname" ] && continue
		new_arg="${new_arg} ${i}"
	done

	for jname in ${jail_list}; do
		bset jname=${jname} ${new_arg}
	done
	exit 0
fi

if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
	readconf cbsd_queue.conf
	[ -z "${cbsd_queue_backend}" ] && MOD_CBSD_QUEUE_DISABLED="1"
fi

update_jails()
{
	[ -z "${i}" ] && return 0
	eval TMPVAL="\$$i"

	# restore spaces from '%' ( see todo in init func from nc.subr for val="one two" )
	#VAL=$( echo "${TMPVAL}" | ${TR_CMD} '%' ' ' )

	case "${i}" in
		vm_ram)
			if is_number ${TMPVAL}; then
				if conv2bytes ${TMPVAL}; then
					TMPVAL="${convval}"
				fi
			else
				# Assume value in MB, convert it to bytes
				TMPVAL=$(( ${TMPVAL} * 1024 * 1024 ))
			fi
			;;
		vm_pid)
			TMPVAL=
			case "${vm_pid}" in
				[Aa][Uu][Tt][Oo])
					. ${subrdir}/bhyve.subr
					check_for_bhyve_process -j ${jname}
					if [ $? -eq 0 ]; then
						TMPVAL=0
					else
						TMPVAL="${vm_pid}"
					fi
					;;
				*)
					TMPVAL="${vm_pid}"
					;;
			esac
			[ -z "${TMPVAL}" ] && err 1 "${N1_COLOR}bset vm_pid: unable to determine pid for: ${N2_COLOR}${jname}${N0_COLOR}"

			if is_number ${TMPVAL}; then
				err 1 "${N1_COLOR}bset vm_pid: not number: ${N2_COLOR}${TMPVAL}${N0_COLOR}"
			fi
			;;
	esac

	case "${i}" in
		com1|com2|com3|com4)
			# LPC database
			blpc jname=${jname} ${i}="${TMPVAL}"
			;;
		tpm)
			# LPC database
			blpc jname=${jname} ${i}="${TMPVAL}"
			# needs to dup ;-(
			SQL_LOCAL_QUERY="${SQL_LOCAL_QUERY}; UPDATE bhyve SET ${i}='${TMPVAL}' WHERE jname='${jname}'"
			SQL_VM_QUERY="${SQL_VM_QUERY}; UPDATE settings SET ${i}='${TMPVAL}'"
			;;
		nice)
			_formfile="${jailsysdir}/${jname}/helpers/brctl.sqlite"
			if [ ! -r ${_formfile} ]; then
				${ECHO} "${N1_COLOR}No such rctl file: ${N2_COLOR}${_formfile}${N0_COLOR}"
				return 1
			fi
			cbsdsqlrw ${_formfile} "UPDATE forms set cur='${TMPVAL}' WHERE param='nice'"
			brenice jname=${jname}
			;;
		vm_pid)
			# pid stored in jails settings as JID (should be moved to settings table)
			SQL_LOCAL_QUERY="${SQL_LOCAL_QUERY}; UPDATE jails SET jid='${TMPVAL}' WHERE jname='${jname}'"
			;;
		gid)
			# pid stored in jails settings as JID (should be moved to settings table)
			SQL_LOCAL_QUERY="${SQL_LOCAL_QUERY}; UPDATE jails SET gid='${TMPVAL}' WHERE jname='${jname}'"
			;;
		soundhw_play|soundhw_rec)
			SQL_VM_QUERY="${SQL_VM_QUERY}; UPDATE bhyve_soundhw SET ${i}='${TMPVAL}'"
			;;
		nic_ratelimit)
			SQL_VM_QUERY="${SQL_VM_QUERY}; UPDATE bhyvenic SET nic_ratelimit='${TMPVAL}' WHERE id='1'"
			;;
		dsk_iops_limit)
			SQL_VM_QUERY="${SQL_VM_QUERY}; UPDATE bhyvedsk SET dsk_iops_limit='${TMPVAL}' WHERE dsk_path='dsk1.vhd'"
			;;
		dsk_mbps_limit)
			SQL_VM_QUERY="${SQL_VM_QUERY}; UPDATE bhyvedsk SET dsk_mbps_limit='${TMPVAL}' WHERE dsk_path='dsk1.vhd'"
			;;
		ip4_addr)
			SQL_VM_QUERY="${SQL_VM_QUERY}; UPDATE settings SET ${i}='${TMPVAL}'"
			# back compatible
			SQL_LOCAL_QUERY="${SQL_LOCAL_QUERY}; UPDATE bhyve SET ${i}='${TMPVAL}' WHERE jname='${jname}'"
			SQL_LOCAL_QUERY="${SQL_LOCAL_QUERY}; UPDATE jails SET ${i}='${TMPVAL}' WHERE jname='${jname}'"
			if [ -f "${jailsysdir}/${jname}/rc.conf_${jname}" ]; then
				# current setting used by cloud-init helper/blogin
				updateconf ${jailsysdir}/${jname}/rc.conf_${jname} ${i}="${TMPVAL}"
			fi
			;;
		*)
			SQL_VM_QUERY="${SQL_VM_QUERY}; UPDATE settings SET ${i}='${TMPVAL}'"
			# back compatible
			SQL_LOCAL_QUERY="${SQL_LOCAL_QUERY}; UPDATE bhyve SET ${i}='${TMPVAL}' WHERE jname='${jname}'"
			;;
	esac

	cbsdlogger NOTICE ${CIX_APP}: ${argpart}: ${TMPVAL}
	[ ${quiet} -ne 1 ] && ${ECHO} "${argpart}: ${N1_COLOR}changed${N0_COLOR}"
}

# here we get status from jstatus, not via jrcconf for non-overwriting params in args
capture jid jstatus jname=${jname}
[ $? -eq 0 ] && err 1 "${N1_COLOR}No such bhyve: ${N2_COLOR}${jname}${N0_COLOR}"

if [ -n "${jconf}" ]; then
	[ ! -r "${jconf}" ] && err 1 "${N1_COLOR}No such jconf file: ${N2_COLOR}${jconf}${N0_COLOR}"
	#jset jname=${jname} `${GREP_CMD} -v '#' ${jconf} | ${GREP_CMD} .| ${TR_CMD} -d ";"`
	my_arg=$( ${GREP_CMD} -v '#' ${jconf} | ${GREP_CMD} . | ${TR_CMD} -d ";" | ${SED_CMD} 's/"/\\"/g' | ${XARGS_CMD} )
	exec /bin/sh << EOF
/usr/local/bin/cbsd bset jname=${jname} "${my_arg}" autorestart=${autorestart}
EOF
	exit 0
fi

if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
	allstr="${@}"
	[ -n "${cbsd_bhyve_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_bhyve_queue_name} id="${jname}" emulator=${emulator} cmd=update ${allstr}
fi

SQL_LOCAL_QUERY=
SQL_VM_QUERY=

for n in ${@}; do
	argpart="${n%%=*}"

	[ "${argpart}" = "jname" ] && continue

	for i in ${JARG}; do
		if [ "${argpart}" = "${i}" ]; then
			update_jails
		fi
	done
done

[ -n "${SQL_LOCAL_QUERY}" ] && cbsdsqlrw local ${SQL_LOCAL_QUERY}
[ -n "${SQL_VM_QUERY}" ] && cbsdsqlrw ${jailsysdir}/${jname}/local.sqlite ${SQL_VM_QUERY}

# exit code 0 is nessesary for dot()
exit 0
