#!/usr/local/bin/cbsd
#v11.1.12
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"
CBSDMODULE="xen"
EXTHELP="wf_bcreate.html"

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

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

readconf buildworld.conf
readconf xen-default-default.conf
readconf zfs.conf

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

init $*

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

really_create_base()
{
	if [ "${vm_os_type}" = "freebsd" -a "${from_jail}" = "1" ]; then
		case ${xen_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
				#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 ""
		#echo "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 prunelist=0 nobase=${nobase} vm_guestfs=${vm_guestfs} fromfile=${temprcconf}"
		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=xen quiet=1 vm_guestfs=${vm_guestfs}
		# 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=$( xen_create_dsk -p ${data}/${defdsk} -s ${imgsize} -f 1 -t ${imgtype} 2>&1 )
		_res=$?
		if [ ${_res} -ne 0 ]; then
			xremove ${jname}
			err 1 "xcreate error: Couldn't create the image file. ${_msg}"
		fi
	fi
}

### MAIN
[ ! -f "$jconf" ] && err 1 "${MAGENTA}no such jconf file${NORMAL}";
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}" ] && 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/xen-default-default.conf ${etcdir}/defaults/${template_profile} ${etcdir}/xen-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}" ] && 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="xen" > /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 ] || 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=xcreate vm_ram=${vm_ram} vm_cpus=${vm_cpus} vm_os_type=${vm_os_type} astart=${astart} protected=${protected} 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)
			err 1 "${MAGENTA}Ip not in pool range${NORMAL}"
			;;
		1)	;;
		2)
			${ECHO} "${MAGENTA}Warning:${GREEN} Ip already exists in LAN${NORMAL}"
			;;
		*)
			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}" ] && 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-xendsk.schema xendsk
/usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-xennic.schema xennic
#/usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-xen-p9shares.schema p9shares
/usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-xen-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 xconfig jname=${jname}${NORMAL}"
${ECHO} "${MAGENTA}To start VM use: ${GREEN}cbsd xstart ${jname}${NORMAL}"
${ECHO} "${MAGENTA}To stop VM use: ${GREEN}cbsd xstop ${jname}${NORMAL}"
${ECHO} "${MAGENTA}To remove VM use: ${GREEN}cbsd xremove ${jname}${NORMAL}"
${ECHO} "${MAGENTA}For attach VM console use: ${GREEN}cbsd xlogin ${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 xendsk ( jname,dsk_controller,dsk_path,dsk_slot  ) VALUES ( \"${jname}\",\"${virtio_type}\",\"${defdsk}\","0" )"
else
	${miscdir}/sqlcli ${jailsysdir}/${jname}/local.sqlite "INSERT INTO xendsk ( jname,dsk_path,dsk_slot  ) VALUES ( \"${jname}\",\"${defdsk}\","0" )"
fi

if [ -n "${nic_driver}" ]; then
	${miscdir}/sqlcli ${jailsysdir}/${jname}/local.sqlite "INSERT INTO xennic ( jname,nic_driver,nic_parent ) VALUES ( \"${jname}\", \"${nic_driver}\", \"${interface}\" )"
else
	${miscdir}/sqlcli ${jailsysdir}/${jname}/local.sqlite "INSERT INTO xennic ( 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
		err 1 "${vm_ram} is not number and we can't convert int via conv2bytes"
	fi
fi

cbsdsql ${jailsysdir}/${jname}/local.sqlite "INSERT INTO settings ( vm_cpus, vm_ram, vm_os_type, vm_boot, vm_os_profile, vm_vnc_port, xen_vnc_tcp_bind, xen_vnc_resolution, cd_vnc_wait, ip4_addr, vnc_password ) VALUES ( \"${vm_cpus}\",\"${vm_ram}\",\"${vm_os_type}\",\"cd\", \"${vm_os_profile}\", \"${vm_vnc_port}\", \"${xen_vnc_tcp_bind}\", \"${xen_vnc_resolution}\", \"${cd_vnc_wait}\",\"${ip4_addr}\",\"${vnc_password}\" )"
cbsdsql local "INSERT INTO xen ( jname, astart, vm_cpus, vm_ram ) VALUES ( \"${jname}\",\"${astart}\",\"${vm_cpus}\",\"${vm_ram}\" )"

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

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=xcreate status=2 data_status=0
fi

exit 0
