#!/usr/local/bin/cbsd
#v11.1.7
MYARG="mode"
MYOPTARG="jname header display options p9device p9path ro"
MYDESC="Manage bhyve 9P (Plan 9 Filesystem Protocol) shared folders"
CBSDMODULE="bhyve"
ADDHELP="
${H3_COLOR}Description${N0_COLOR}:

bhyve-p9shares manage directories that CBSD uses as shared folders to exchange files between virtual 
machines or between virtual machine and a host system via 9P (or the Plan 9 Filesystem Protocol).
Working with shared folders will only be available if your guest OSs have support for mounting the 
9P file system via virtio, see examples.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}mode=${N0_COLOR}         - several possibilities:
      'list'   - show shares.
      'attach' - attach shared folder to jname, p9device= and p9path= required.
      'detach' - detach shared folder from jname, p9device= required;
 ${N2_COLOR}options=${N0_COLOR}      - custom 9p-device-options, see man bhyve(8);
 ${N2_COLOR}p9device=${N0_COLOR}     - share name, one-word;
 ${N2_COLOR}p9path=${N0_COLOR}       - shared folders path;
 ${N2_COLOR}ro=${N0_COLOR}           - when '1' or 'true' - expose the share in read-only mode,
                 default is '0' - RW mode;
 ${N2_COLOR}header=${N0_COLOR}       - when '0' - don't print header;
 ${N2_COLOR}display=${N0_COLOR}      - list by comma for column, 
                 default: 'jname,p9path,p9device,ro',
                   additional: 'options';

${H3_COLOR}Examples${N0_COLOR}:

  1) run Debian cloud VM (set correct ci_gw4 as gateway and ci_ip4_addr if necessary):
  # cbsd bcreate jname=deb9p vm_ram=2g vm_cpus=1 vm_os_type=linux vm_os_profile=cloud-Debian-x86-11 imgsize=20g ci_ip4_addr=DHCP ci_gw4=10.0.1.3

  2) create share:
  # mkdir -p /var/cache/share1

  3) add/attach /var/cache/share1 as 'share1' to deb9p vm:
  # cbsd bhyve-p9shares mode=attach p9device=share1 p9path=/var/cache/share1 jname=deb9p

  4) start VM:
  # cbsd bstart deb9p

  5) login into VM:
  # cbsd blogin deb9p

  6) mount share:
  # mount -t 9p -o trans=virtio sharename /mnt

  # read-only mode:
  # cbsd bhyve-p9shares mode=attach ro=true p9device=share1 p9path=/var/cache/share1 jname=deb9p

"

. ${subrdir}/nc.subr
. ${subrdir}/virtual.subr
oro=
ro=
ooptions=
options=
. ${cbsdinit}
[ -n "${ro}" ] && oro="${ro}"
[ -z "${ro}" ] && ro="0"		# default mode: RW
[ -n "${options}" ] && ooptions="${options}"
[ -z "${options}" ] && options="0"

. ${system}

[ -z "${display}" ] && display="jname,p9path,p9device,ro"

#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

	_status=

	#populate values for in output string
	for _i in ${mydisplay}; do
		_val=""
		eval _val=\$$_i
		[ -z "${_val}" ] && return 0

		if [ -z "${_status}" ]; then
			_status="${N0_COLOR}${_val}"
		else
			_status="${_status} ${_val}"
		fi
	done
}


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

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

	[ -n "${2}" ] && local jname="${2}"

	_status=
	_sql="SELECT p9path,p9device,ro,options FROM p9shares"
	cbsdsqlro ${sqlfile} ${_sql}| while read p9path p9device ro options; do
		populate_output_data
		printf "${N2_COLOR}"
		printf "${_status}"
		printf "${N0_COLOR}\n"
	done
}


# return 1 if p9device record exist
#  $p9device, $mydb must be set
share_exist()
{
	local _tmp

	_tmp=$( cbsdsqlro ${mydb} SELECT p9path FROM p9shares WHERE p9device=\"${p9device}\" 2>/dev/null )

	if [ -n "${_tmp}" ]; then
		return 0
	else
		return 1
	fi
}

show_shares()
{
	show_header

	for i in ${jname}; do
		mydb="${jailsysdir}/${i}/local.sqlite"
		show_jaildata_from_sql ${mydb} ${i}
	done

	return 0
}

[ -z "${header}" ] && header=1
sqldelimer=" "

case "${mode}" in
	list)
		[ -z "${jname}" ] && jname=$( ${miscdir}/sqlcli ${dbdir}/local.sqlite "SELECT jname FROM jails WHERE emulator = \"bhyve\"" )
		show_shares | ${COLUMN_CMD} -t
		;;
	attach)
		[ -z "${jname}" ] && err 1 "${N1_COLOR}Please set ${N2_COLOR}jname=${N0_COLOR}"
		[ -z "${p9path}" -o -z "${p9device}" ] && err 1 "${N2_COLOR}p9path= ${N1_COLOR}and ${N2_COLOR}p9device=${N1_COLOR} must be set${N0_COLOR}"
		mydb="${jailsysdir}/${jname}/local.sqlite"

		if share_exist; then
			err 1 "${N1_COLOR}Share with p9device=${N2_COLOR}${p9device}${N1_COLOR} already exist${N0_COLOR}"
		fi

		[ ! -d ${p9path} ] && err 1 "${N1_COLOR}Path not exist: ${N2_COLOR}${p9path}${N0_COLOR}"

		[ -n "${oro}" ] && ro="${oro}"
		case "${ro}" in
			0)
				ro="false"
				;;
			1)
				ro="true"
				;;
		esac
		cbsdsqlrw ${mydb} "INSERT INTO p9shares ( p9path, p9device, ro, options ) VALUES ( \"${p9path}\", \"${p9device}\", \"${ro}\", \"${options}\" )"
		${ECHO} "${N1_COLOR}Attached${N0_COLOR}" 2>&1
		;;
	detach)
		[ -z "${jname}" ] && err 1 "${N1_COLOR}Please set ${N2_COLOR}jname=${N0_COLOR}"
		[ -z "${p9device}" ] && err 1 "${N2_COLOR}${N2_COLOR}p9device=${N1_COLOR} must be set${N0_COLOR}"
		mydb="${jailsysdir}/${jname}/local.sqlite"

		if share_exist; then
			cbsdsqlrw ${mydb} "DELETE FROM p9shares WHERE p9device=\"${p9device}\""
		else
			err 1 "${N1_COLOR}Share with p9device=${N2_COLOR}${p9device}${N1_COLOR} not exist${N0_COLOR}"
		fi
		cbsdsqlrw ${mydb} "DELETE FROM p9shares WHERE p9device=\"${p9device}\""
		${ECHO} "${N1_COLOR}Dettached${N0_COLOR}" 2>&1
		;;
	*)
		err 1 "${N1_COLOR}Unknown mode: ${N2_COLOR}${mode}${N0_COLOR}"
esac

exit 0
