#!/usr/local/bin/cbsd
#v11.0.15
MYARG="jconf"
MYOPTARG="inter ver arch customskel fstablocal delpkglist removejconf pkglist jprofile zfs_snapsrc"
MYDESC="Create jail from config file"
ADDHELP="inter=0 to prevent any questions and to accept answers by default\n\
customskel = additional skel directory applyed above jail structrure\n\
fstablocal = additional fstab file stored as fstab.local\n\
jprofile = specify jail profile for creating jail\n\
zfs_snapsrc = use ZFS snapshot as data source\n\
removejconf= 0,1: remove jconf after jcreate? 0 - don't remove\n"

CBSDMODULE="bhyve"
EXTHELP="wf_bcreate.html"

. ${subr}
. ${system}
. ${tools}
. ${mdtools}
. ${jfs}

[ -z "${cbsd_queue_name}" ] && cbsd_queue_name="/clonos/bhyvevms/"

readconf buildworld.conf
readconf bhyve-default-default.conf
readconf zfs.conf

. ${workdir}/universe.subr
. ${workdir}/freebsd_world.subr
. ${workdir}/bhyve.subr

init $*

[ -n "${removejconf}" ] && oremovejconf="${removejconf}"

really_create_base()
{
	if [ "${vm_os_type}" = "freebsd" -a "${from_jail}" = "1" ]; then
		case ${vm_os_profile} in
			"FreeBSD-bsdinstall-jail")
				export UNAME_r="${ver}-RELEASE"
				export DISTRIBUTIONS="kernel.txz base.txz"
				bsdinstall jail ${data}
				unset UNAME_r
				nobase=1
				;;
			*)
				nobase=0 # 0 for jail2iso
				init_target_arch
				init_basedir
				init_kerneldir
				get_base
				get_kernel
				${ECHO} "${MAGENTA}Stage1: ${GREEN}jcreate...${NORMAL}"
				echo "jcreate jconf=${temprcconf} pkg_bootstrap=0"
				jcreate jconf=${temprcconf} pkg_bootstrap=0

#				populate_freebsd_world
#				populate_freebsd_kernel
				customskel
				;;
		esac
	fi
}

really_create_vm()
{
	local _res _msg

	#test for imgtype
	case ${zfsfeat} in
			1)
				;;
			*)
				# force switch imgtype to md when no zfsfeat
				imgtype="md"
	esac

	if [ "${from_jail}" ]; then
		${ECHO} "${MAGENTA}Stage2: ${GREEN}jail2iso...${NORMAL}"
		[ -z "${swapsize}" ] && swapsize="0"

		mountbase -o "" -p "" -d "" -c "" -s ""
		jail2iso jname=${jname} nameserver=${jnameserver} ip4_addr=${ip4_addr} gw4=${gw4} dstname=${jname}.$$.img swapsize=${swapsize} freesize=${imgsize} dstdir=/tmp host_hostname="${host_hostname}" media=bhyve quiet=1 vm_guestfs=${vm_guestfs} efi=1
		# fromfile=${temprcconf} addmod=0

		jremove ${jname}
		create_fs ${data}

		#test for zfs mounted & mount if not
		case ${zfsfeat} in
			1)
				. ${zfstool}
				zfsmnt ${data}
				[ $? -eq 2 ] && /sbin/zfs mount "${ZPOOL}"
				;;
		esac

		${SYSRC_CMD} -qf ${jconf} ver="${ver}" > /dev/null
		/bin/mv /tmp/${jname}.$$.img ${data}/${defdsk}
	else
		_msg=$( bhyve_create_dsk -p ${data}/${defdsk} -s ${imgsize} -f 1 -t ${imgtype} 2>&1 )
		_res=$?
		if [ ${_res} -ne 0 ]; then
			bremove ${jname}
			log_err 1 "bcreate error: Couldn't create the image file. ${_msg}"
		fi
	fi
}


### MAIN
[ ! -f "${jconf}" ] && log_err 1 "${MAGENTA}no such jconf file${NORMAL}";
st_time=$( /bin/date +%s )
over="${ver}"
oarch="${arch}"
jconf=$( /bin/realpath ${jconf} )

if [ -z "${delpkglist}" ]; then
	delpkglist=0
else
	delpkglist=1
fi

temprcconf="${ftmpdir}/jcreate_jconf.$$"

# TRIM DOS CRLF
/bin/cat ${jconf} |/usr/bin/tr -d \\r > ${temprcconf}

. ${buildconf}
. ${temprcconf}

# profile
[ -z "${vm_os_profile}" ] && log_err 1 "${MAGENTA}No such profile: ${GREEN}vm-${vm_os_type}-${vm_os_profile}.conf${NORMAL}"

template_profile=

# Merge with default and profile settings
[ -n "${vm_os_profile}" -a -n "${vm_os_type}" ] && template_profile="vm-${vm_os_type}-${vm_os_profile}.conf"

conf_owner=$( /usr/bin/stat -f "%u" ${jconf} )
conf_group=$( /usr/bin/stat -f "%g" ${jconf} )

/usr/bin/truncate -s0 ${jconf}

for merge_me in ${etcdir}/defaults/bhyve-default-default.conf ${etcdir}/defaults/${template_profile} ${etcdir}/bhyve-default-default.conf ${etcdir}/${template_profile} ${temprcconf}; do
	[ ! -r "${merge_me}" ] && continue;
	tmp_merge=$( /usr/bin/mktemp )
	merge from=${jconf} to=${merge_me} out=${tmp_merge}
	[ -f ${tmp_merge} ] && /bin/mv ${tmp_merge} ${jconf}
done

# make permission for group write
/usr/sbin/chown ${conf_owner}:${conf_group} ${jconf}

. ${jconf}

[ -n "${oremovejconf}" ] && removejconf="${oremovejconf}"

if [ ${removejconf} = "1" ]; then
	trap "/bin/rm -f ${temprcconf} ${jconf}" HUP INT ABRT BUS TERM  EXIT
else
	trap "/bin/rm -f ${temprcconf}" HUP INT ABRT BUS TERM  EXIT
fi

[ -z "${jname}" ] && log_err 1 "${MAGENTA}No such jname variable${NORMAL}"

if [ "${vm_os_type}" = "freebsd" -a "${from_jail}" = "1" ]; then
	# change emulator type for jcreate
	${SYSRC_CMD} -qf ${jconf} emulator="jail" > /dev/null 2>&1

	if [ -n "${jprofile}" ]; then
		. ${settingstui}
		if [ -r "${etcdir}/jail-freebsd-${jprofile}.conf" ]; then
			${ECHO} "${MAGENTA}Use profile: ${GREEN}${etcdir}/jail-freebsd-${jprofile}.conf${NORMAL}"
			merge_apply_profiles ${etcdir}/jail-freebsd-${jprofile}.conf ${jconf}
		elif [ -r "${etcdir}/defaults/jail-freebsd-${jprofile}.conf" ]; then
			${ECHO} "${MAGENTA}Use profile: ${GREEN}${etcdir}/defaults/jail-freebsd-${jprofile}.conf${NORMAL}"
			merge_apply_profiles ${etcdir}/defaults/jail-freebsd-${jprofile}.conf ${jconf}
		fi
	fi

	${SYSRC_CMD} -qf ${jconf} emulator="bhyve" > /dev/null 2>&1
fi

# re-read jail params and apply personal after profile
. ${jconf}

# apply pkglist from tpl_pkglist
[ -n "${tpl_pkglist}" ] && ${SYSRC_CMD} -qf ${jconf} pkglist="${tpl_pkglist}" > /dev/null 2>&1

jstatus jname=${jname} > /dev/null 2>&1
[ $? -eq 0 ] || log_err 1 "${MAGENTA}Jail with ${jname} already exist${NORMAL}"

# CBSD QUEUE
if [ -x "${moduledir}/cbsd_queue.d/cbsd_queue" ]; then
	[ "${cbsd_queue_name}" != "none" ] && cbsd_queue cbsd_queue_name=${cbsd_queue_name} id=${jname} cmd=bcreate vm_ram=${vm_ram} vm_cpus=${vm_cpus} vm_os_type=${vm_os_type} astart=${astart} protected=${protected} vnc_port='0' status=1
fi

# ip validate
if [ -n "${interface}" -a "${inteface}" != "0" ]; then
	### CHECK FOR IP ( 1 - check for interfaces) ####
	checkip ip=${ips} check=1 > /dev/null 2>&1
	case $? in
		0)
			log_err 1 "${MAGENTA}Ip not in pool range${NORMAL}"
			;;
		1)	;;
		2)
			${ECHO} "${MAGENTA}Warning:${GREEN} Ip already exists in LAN${NORMAL}"
			;;
		*)
			log_err 1 "Unknown code from checkip"
			;;
	esac
fi

#${ECHO} "${MAGENTA}Please wait: ${GREEN}this will take a while...${NORMAL}"

[ -d "${data}" ] && removedata ${data}

defdsk="dsk1.vhd"
defnic="nic1.vhd"

if [ -z "${zfs_snapsrc}" ]; then
	really_create_base
	really_create_vm
	/bin/cp ${jconf} ${rcconf}
else
	create_fs ${data}
fi

[ ! -d "${data}" ] && log_err 1 "Can't create datadir ${data}"
[ ! -d ${path} -a "${baserw}" -eq 0 ] && /bin/mkdir -p ${path}
[ ! -d ${jailfstabdir}  ] && /bin/mkdir -p ${jailfstabdir}
[ ! -d "${jailsysdir}/${jname}" ] && /bin/mkdir -p ${jailsysdir}/${jname}

/usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-bhyvedsk.schema bhyvedsk
/usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-bhyve-dskcontroller.schema bhyve_dskcontroller
/usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-bhyvenic.schema bhyvenic
/usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-bhyve-p9shares.schema p9shares
/usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-bhyve-cpu_topology.schema cpu_topology
/usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-bhyve-settings.schema settings

[ -n "${fstablocal}" -a -f "${fstablocal}" ] && /bin/cp ${fstablocal} ${jailfstabdir}/${jailfstabpref}${jname}.local

/bin/cp ${jconf} ${rcconf}
. ${rcconf}

# Finnaly export to SQLite
jregister jname=${jname} mode=new

_res=$?

if [ ${_res} -ne 0 ]; then
	${ECHO}
	${ECHO} "${MAGENTA}Creating ${jname} failed: ${GREEN}cbsd jregister${NORMAL}"
	${ECHO} "${MAGENTA}Please review bad config file: ${GREEN}/tmp/rc.conf_${jname}${NORMAL}"
	/bin/mv ${rcconf} /tmp
	#cleanup
	[ -f "${mount_fstab}" ] && /bin/rm -f ${mount_fstab}
	removedata ${data}
	exit 1
fi

echo
${ECHO} "${MAGENTA}To edit VM properties use: ${GREEN}cbsd bconfig jname=${jname}${NORMAL}"
${ECHO} "${MAGENTA}To start VM use: ${GREEN}cbsd bstart ${jname}${NORMAL}"
${ECHO} "${MAGENTA}To stop VM use: ${GREEN}cbsd bstop ${jname}${NORMAL}"
${ECHO} "${MAGENTA}To remove VM use: ${GREEN}cbsd bremove ${jname}${NORMAL}"
${ECHO} "${MAGENTA}For attach VM console use: ${GREEN}cbsd blogin ${jname}${NORMAL}"
echo
${ECHO} "${MAGENTA}Creating ${jname} complete: ${GREEN}Enjoy!${NORMAL}"

/bin/rm -f ${rcconf}

[ "${mdsize}" != "0" ] && unmountmd jroot=${data}

if [ -n "${virtio_type}" ]; then
	${miscdir}/sqlcli ${jailsysdir}/${jname}/local.sqlite "INSERT INTO bhyvedsk ( jname,dsk_controller,dsk_path,dsk_slot  ) VALUES ( \"${jname}\",\"${virtio_type}\",\"${defdsk}\","0" )"
else
	${miscdir}/sqlcli ${jailsysdir}/${jname}/local.sqlite "INSERT INTO bhyvedsk ( jname,dsk_path,dsk_slot  ) VALUES ( \"${jname}\",\"${defdsk}\","0" )"
fi

if [ -n "${nic_driver}" ]; then
	${miscdir}/sqlcli ${jailsysdir}/${jname}/local.sqlite "INSERT INTO bhyvenic ( jname,nic_driver,nic_parent ) VALUES ( \"${jname}\", \"${nic_driver}\", \"${interface}\" )"
else
	${miscdir}/sqlcli ${jailsysdir}/${jname}/local.sqlite "INSERT INTO bhyvenic ( jname,nic_parent ) VALUES ( \"${jname}\", \"${interface}\" )"
fi

# Check if SIZE if valid: can't be smaller then template
if is_number ${vm_ram}; then
	# not number, try to convert
	if conv2bytes "${vm_ram}"; then
		vm_ram="${convval}"
	else
		log_err 1 "${vm_ram} is not number and we can't convert int via conv2bytes"
	fi
fi

if [ -n "${register_iso_as}" -a -n "${register_iso_name}" ]; then
	cd_name="${register_iso_as}"
	cd_path="${srcdir}/iso/${register_iso_name}"

	cd_rec_num=$( cbsdsql storage_media SELECT COUNT\(path\) FROM media WHERE name=\"${cd_name}\" AND path=\"${cd_path}\" AND type=\"iso\" AND jname=\"-\" )

	if [ "${cd_rec_num}" = "0" ]; then
		# register new ISO with assignment to this VM
		media mode=register name="${register_iso_as}" path="${srcdir}/iso/${register_iso_name}" type=iso jname=${jname}
	else
		# we have free/unassignent CD. link to this VM
		cbsdsql storage_media "UPDATE media SET jname=\"${jname}\" WHERE jname=\"-\" AND type=\"iso\" AND name=\"${cd_name}\" AND path=\"${cd_path}\""
	fi

#	media mode=register name="${register_iso_as}" path="${srcdir}/iso/${register_iso_name}" type=iso jname=${jname}
fi

[ ! -d ${jailsysdir}/${jname} ] && /bin/mkdir -p ${jailsysdir}/${jname}
[ ! -d ${jailsysdir}/${jname}/etc ] && /bin/mkdir -p ${jailsysdir}/${jname}/etc

system_dir="stop.d \
start.d \
master_prestop.d \
master_prestart.d \
master_poststop.d \
master_poststart.d \
remove.d"

for i in ${system_dir}; do
	if [ -n "${systemskeldir}" -a "${systemskeldir}/${i}" ]; then
		/bin/cp -a ${systemskeldir}/${i} ${jailsysdir}/${jname}/${i}
	else
		[ ! -d "${i}"  ] && /bin/mkdir -m 0775 -p ${jailsysdir}/${jname}/${i}
	fi
	/usr/sbin/chown ${cbsduser}:${cbsduser} ${jailsysdir}/${jname}/${i}
done

# store profile in jail system dir
storeconf vm-${vm_os_type}-${vm_os_profile}.conf ${jailsysdir}/${jname}/etc/vm-${vm_os_type}-${vm_os_profile}.conf

# create ascii rc.conf file for overwriting values
/bin/cat > ${jailsysdir}/${jname}/etc/rc.conf <<EOF
# The parameters in this file can overwrite the settings from SQLite3 or global params
# e.g:
# bhyve_flags="-p 1:1 -p 2:2"
EOF

jcleanup jname=${jname}

if [ -x "${moduledir}/cbsd_queue.d/cbsd_queue" ]; then
	[ "${cbsd_queue_name}" != "none" ] && cbsd_queue cbsd_queue_name=${cbsd_queue_name} id="${jname}" cmd=bcreate status=2 data_status=0
fi

end_time=$( /bin/date +%s )
cbsdlogger NOTICE ${CBSD_APP}: vm ${jname} has been created in $(( end_time - st_time ))s

exit 0
