#!/usr/local/bin/cbsd
#v11.1.11
MYARG="jconf"
MYOPTARG="inter ver arch customskel fstablocal delpkglist removejconf pkglist jprofile zfs_snapsrc pkg_bootstrap autorestart runasap"
MYDESC="Create jail from config file. If jail exist and autorestart=1 - jset will be used to update params."
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\
pkg_bootstrap= 0,1; overwrite pkg_bootstrap from conf file.\n\
removejconf= 0,1: remove jconf after jcreate? 0 - don't remove\n"
CBSDMODULE="jail"
EXTHELP="wf_jcreate.html"

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

init $*

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

mkfstab()
{
	if [ ${baserw} -eq 0 ]; then
		/bin/cat > ${mount_fstab} << EOF
# Please do not edit this file for additional fstabs
# Use ${jailfstabdir}/${jailfstabpref}${jname}.local instead
${data}/etc /etc ${NULLFS} rw 0 0
${data}/root /root ${NULLFS} rw 0 0
${data}/tmp /tmp ${NULLFS} rw 0 0
${data}/usr/home /usr/home ${NULLFS} rw 0 0
${data}/usr/local /usr/local ${NULLFS} rw 0 0
${data}/compat /compat ${NULLFS} rw 0 0
${data}/var /var ${NULLFS} rw 0 0
#
EOF
	fi

	/usr/bin/touch ${mount_fstab}.local
}

install_and_apply_helpers()
{
	local _srcfile="${1}"

	local module=$( cbsdsql ${_srcfile} SELECT helpername FROM system |/usr/bin/awk '{printf $1}' )

	${ECHO} "${MAGENTA}Install and apply helpers ${_srcfile}: ${GREEN}${module}${NORMAL}"

	local helperdir="${jailsysdir}/${jname}/helpers"

	[ ! -d "${helperdir}" ] && /bin/mkdir -p ${helperdir}

	local formfile="${helperdir}/${module}.sqlite"

	echo ":: /bin/cp -a ${_srcfile} ${formfile}"
	/bin/cp -a ${_srcfile} ${formfile}

	echo ":: forms module=${module} mode=apply jname=${jname} inter=0"
	forms module=${module} mode=apply jname=${jname} inter=0
}


### MAIN
st_time=$( /bin/date +%s )
[ -n "${delpkglist}" ] && odelpkglist="${delpkglist}"
# push pkg_bootstrap to orig_ variable
[ -n "${pkg_bootstrap}" ] && orig_pkg_bootstrap="${pkg_bootstrap}"
[ -z "${cbsd_queue_name}" ] && cbsd_queue_name="/clonos/jailscontainers/"

readconf zfs.conf
readconf buildworld.conf
readconf jail-freebsd-default.conf

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

[ ! -f "${jconf}" ] && err 1 "${MAGENTA}no such jconf file${NORMAL}";

jconf=$( /bin/realpath ${jconf} )

[ -z "${delpkglist}" ] && delpkglist=0

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

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

. ${temprcconf}

# 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=jcreate ip4_addr=${ip4_addr} protected=${protected} vnc_port=0 status=1
fi

over="${ver}"
# Determine stable value. Must be after buildconf
strpos --str="${over}" --search="."

# auto-detect for stable/release
pos=$?
if [ ${pos} -eq 0 ]; then
	stable=1
	ostable=1
else
	stable=0
	ostable=0
fi

# re-read default tpl for apply dynamic variable with $jname
readconf jail-freebsd-default.conf

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

fi

. ${temprcconf}

# apply pkglist from tpl_pkglist
if [ -n "${tpl_pkglist}" ]; then
	${SYSRC_CMD} -qf ${temprcconf} pkglist="${tpl_pkglist}" > /dev/null 2>&1
	pkglist="${tpl_pkglist}"
fi

. ${buildconf}

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

init_jail_path
init_target_arch
init_basedir
init_kerneldir

jstatus jname=${jname} > /dev/null 2>&1

if [ $? -ne 0 ]; then
	[ ${autorestart} -eq 0 ] && err 1 "${MAGENTA}Jail with ${jname} already exist. Use autorestart=1 for updating via jset${NORMAL}"
	jset jname=${jname} jconf=${jconf} autorestart=1

	# 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=jcreate ip4_addr=${ip4_addr} astart=${astart} protected=${protected} vnc_port=0 status=2
	fi

	exit 0
fi

case "${emulator}" in
	qemu-aarch64-static)
		arch="arm64"
		target_arch="aarch64"
		;;
esac

get_base

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

[ -d "${data}" ] && removedata ${data}
[ ! -d ${path} -a "${baserw}" -eq 0 ] && /bin/mkdir -p ${path}

[ -z "${jailsysskeldir}" ] && jailsysskeldir="${sharedir}/${platform}-${emulator}-${jail_profile}-system-skel"

if [ -d "${jailsysskeldir}" ]; then
	# we have custom skeldir. copy
	${ECHO} "${MAGENTA}Applying custom skel system dir template from: ${GREEN}${jailsysskeldir}${MAGENTA}"
	/bin/cp -a ${jailsysskeldir} ${jailsysdir}/${jname}
	# local fstab ?
	[ -f "${jailsysskeldir}/fstab.local" ] && fstablocal="${jailsysskeldir}/fstab.local"
fi

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

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}" ]; then
		if [ -d "${systemskeldir}/${i}" ]; then
			/bin/cp -a ${systemskeldir}/${i} ${jailsysdir}/${jname}/${i} > /dev/null 2>&1
		fi
	else
		[ ! -d "${i}"  ] && /bin/mkdir -m 0775 -p ${jailsysdir}/${jname}/${i}
	fi
	/usr/sbin/chown ${cbsduser}:${cbsduser} ${jailsysdir}/${jname}/${i}
done

## MD backend place
if [ "${mdsize}" != "0" ]; then
	conv2bytes "${mdsize}" || err 1 "conv2bytes error from ${mdsize}"
	imgbytes=${convval}
	blockcount=$(( imgbytes  / 1048576 ))
	mdimage="${jailsysdir}/${jname}/image.dat"
	/usr/bin/touch "${mdimage}"
	/bin/dd if="/dev/zero" of="${mdimage}" bs=1m count=0 seek=${blockcount} 1> /dev/null 2>&1 || err 1 "jcreate error: couldn't create the image file. ${mdimage}"
	# Attach the .img file as a memory disk.
	mdimagedevice=$( /sbin/mdconfig -a -t vnode -f "${mdimage}" )
	[ $? -eq 0 ] || err 1 "Error: Failed to mdconfig on ${mdimage}"
	/sbin/newfs -j -n -U "/dev/${mdimagedevice}" 1> /dev/null 2>&1 || /sbin/mdconfig -d -u ${mdimagedevice} || err 1 "Error: Couldn't newfs the memory disk. ${mdimagedevice}"
	/sbin/mdconfig -d -u ${mdimagedevice}
	# mount here
	mountmd jroot=${data} mdfile=${mdimage}
fi
## MD backend

create_fs ${data}
[ $? -ne 0 ] && err 1 "${MAGENTA}create_fs failed${NORMAL}"
[ ! -d "${data}" ] && err 1 "Can't create datadir ${data}"

if [ -z "${zfs_snapsrc}" ]; then
	populate_freebsd_world
fi

customskel
mkfstab

case "${ip4_addr}" in
	[Dd][Hh][Cc][Pp])
		ip4_addr=$( dhcpd )
		[ $? -eq 2 ] && err 1 "${MAGENTA}No free IP address for DHCP in nodeippool${NORMAL}"
		${SYSRC_CMD} -qf ${temprcconf} ip4_addr="${ip4_addr}" > /dev/null
		# 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=update ip4_addr=${ip4_addr} vnc_port=0 status=1
		fi
		;;
esac

${SYSRC_CMD} -qf ${temprcconf} arch="${arch}" > /dev/null
${SYSRC_CMD} -qf ${temprcconf} ver="${ver}" > /dev/null
${SYSRC_CMD} -qf ${temprcconf} stable="${stable}" > /dev/null

# update with normalize path
${SYSRC_CMD} -qf ${temprcconf} path="${path}" > /dev/null
${SYSRC_CMD} -qf ${temprcconf} mount_fstab="${mount_fstab}" > /dev/null
${SYSRC_CMD} -qf ${temprcconf} rcconf="${rcconf}" > /dev/null
${SYSRC_CMD} -qf ${temprcconf} data="${data}" > /dev/null

/bin/cp ${temprcconf} ${rcconf}

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

# Finnaly export to SQLite
jregister jname=${jname} mode=new status=3
res=$?

if [ ${res} -eq 0 ]; then
	. ${workdir}/jcreate.subr

	jswmode jname=${jname} mode=maintenance comment='Jail Initialization...'

	# pkg bootstrap && user accounting
	if [ "${ver}" != "empty" ]; then
		postcreate_module_action ${jname} ${jconf}
	fi

	echo
	${ECHO} "${MAGENTA}To edit VM properties use: ${GREEN}cbsd jconfig jname=${jname}${NORMAL}"
	${ECHO} "${MAGENTA}To start VM use: ${GREEN}cbsd jstart ${jname}${NORMAL}"
	${ECHO} "${MAGENTA}To stop VM use: ${GREEN}cbsd jstop ${jname}${NORMAL}"
	${ECHO} "${MAGENTA}To remove VM use: ${GREEN}cbsd jremove ${jname}${NORMAL}"
	${ECHO} "${MAGENTA}For attach VM console use: ${GREEN}cbsd jlogin ${jname}${NORMAL}"
	echo
	${ECHO} "${MAGENTA}Creating ${jname} complete: ${GREEN}Enjoy!${NORMAL}"

	/bin/rm -f ${rcconf}

	[ "${mdsize}" != "0" ] && unmountmd jroot=${data}
else
	${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

for i in ${with_img_helpers}; do

	jswmode jname=${jname} mode=master comment='0'

	if [ ! -r "${i}" ]; then
		${ECHO} "${MAGENTA}Helper doesn't available by path: ${GREEN}${i}${NORMAL}"
		continue
	fi

	install_and_apply_helpers ${i}
done

[ ! -r ${jailsysdir}/${jname}/local.sqlite ] && /usr/local/bin/cbsd ${miscdir}/updatesql ${jailsysdir}/${jname}/local.sqlite ${distdir}/share/local-jailnic.schema jailnic

if [ -n "${nic_hwaddr}" ]; then
	cbsdsql ${jailsysdir}/${jname}/local.sqlite "INSERT INTO jailnic ( name,nic_order,nic_slot,nic_parent,nic_hwaddr ) VALUES ( \"epairb\",\"0\",\"0\",\"auto\",\"${nic_hwaddr}\" )"
fi

jswmode jname=${jname} mode=master comment='0'

# autostart asap upon jail created
[ "${runasap}" = "1" ] && jstart ${jname}

myjid=$( cbsdsql local SELECT jid FROM jails WHERE jname=\"${jname}\" 2>/dev/null )

[ -z "${myjid}" ] && myjid=0

if [ ${myjid} -eq 0 ]; then
	data_status=0
else
	data_status=1
fi

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

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

exit 0
