#!/usr/local/bin/cbsd
# shellcheck shell=sh
# shellcheck disable=SC2154,SC2034,SC1090,SC1091,SC3043,SC2166,SC2086
# v13.0.8
CIXARG=""
# should be in sync with run_jail() func: tools/up script
CIXOPTARG="autorestart ci_gw4 ci_gw42 ci_interface2 ci_interface_mtu ci_interface_mtu2 ci_ip4_addr ci_ip4_addr2 \
ci_user_pubkey customskel delpkglist environment etcupdate_init flavor from fstablocal inter interface2 jconf \
jname jprofile nic_hwaddr nic_mtu nic_flags nic_vlan_untagged nic_vlan_tagged nic2_flags pkg_bootstrap pkglist quiet \
removejconf runasap sysrc zfs_snapsrc jailsysskeldir platform"
# allow all jail settings
. ${distsharedir}/jail-arg
[ "${racct}" = "1" ] && . ${distsharedir}/rctl.conf
JAIL_ARGS="${JARG}"
CIXOPTARG="${CIXOPTARG} ${JAIL_ARGS}"
MYDESC="Create jail from config file or args"
ADDHELP="
${H3_COLOR}Description${N0_COLOR}:

The jail is created according to configuration file generated by jconstruct-tui.
You can see this configuration file if you answer negatively to the 
'Do you want to create jail immediately?' question at the end of the dialogue.

To use CARP without VNET with jail ( in 'vhid_X#<IP_ADDR> form' for ip4_addr= ), please
use 'cbsd vhidcfg-tui' first.

Please keep in mind if you use Linux-based profile: only 'devuan' allows services inside 
jail to start at startup, since Devuan uses SysVinit.

If the 'buildah' package is installed on the system, you can use the OCI images 
(including Linux) from the official docker registry - see the examples section 
with the [*] marker.

In addition, you can override all parameters via command line arguments.
Many parameters are set by default via profiles, 
e.g: ~cbsd/etc/defaults/jail-freebsd-default.conf which can be overwrited via
~cbsd/etc/jail-freebsd-default.conf or personal profile.

You can create your own profile and specify it when creating the container.

If jail exist and autorestart=1 - jset will be used to update params.
 If the container is running and any parameter has been changed, the container will be restarted.
 Mostly useful for management system (Ansible/Puppet/Salt) which generate the container template.

If you use 'zfs_encryption' settings, you may want to customize 'zfs_always_unload_key' settings
via ~cbsd/etc/zfs.conf (globally) or ~cbsd/jails-system/<jail>/etc/zfs.conf (per jail) to unload
key to unload the key every time the container stops.

Alternative methods of creating jail:
  CBSDfile, 'cbsd jconstruct', 'cbsd jconstruct-tui'.

To get available 'jprofile' profiles list, just checkout 
  ~cbsd/etc/defaults/jail-freebsd-XXXX.conf files, e.g.:

 ls ~cbsd/etc/defaults/ | grep '^jail-freebsd-' | sed 's/jail-freebsd-//g;s/.conf//g'

${H3_COLOR}  Environment Variables${N0_COLOR}:

Environment variables are stored in the ~cbsd/jails-system/\$jname directory in files:

  - environment ( usually this file is copied from system SKEL directory )
  - environment.local ( for custom user's env )

If you use an environment= arguments, these values are added to ~cbsd/jails-system/\$jname/environment file 


${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}ci_user_pubkey${N0_COLOR}  - full/relative path to authorized_keys or may contain pubkey 
                   string itself, e.g: ci_user_pubkey=\"ssh-ed25519 XXXXX root@my.domain\".
                   This options will customize /root/.ssh/authorized_keys in jail.
                   When 'ci_user_pubkey=authorized_keys', ~cbsd/.ssh/id_rsa.pub file will be used;
 ${N2_COLOR}ci_gw4=${N0_COLOR}         - 0,IP to disable: manage/set defaultrouter= settings in jail rc.conf (for vnet).
 ${N2_COLOR}emulator=${N0_COLOR}       - specify emulator engine (e.g. for qemu-user mode or linuxulator;
 ${N2_COLOR}environment${N0_COLOR}     - pass environment, e.g.: 'environment=\"FOO=bar\" environment=\"VAR1=boo\"'
                   or path to 'env' file;
 ${N2_COLOR}etcupdate_init=${N0_COLOR} - 1(enable),0(disable) for etcupdate init (overwrite config values).
 ${N2_COLOR}flavor${N0_COLOR}          - Use flavor (named group of vm_cpus/vm_ram/imgsize): see 'cbsd vm-packages';
 ${N2_COLOR}from=${N0_COLOR}           - <url> or MD5 of image to create jail from CBSD image.
 ${N2_COLOR}inter=${N0_COLOR}          - 0 to prevent any questions and to accept answers by default.
 ${N2_COLOR}customskel=${N0_COLOR}     - <path>: additional skel directory applyed above jail structrure.
 ${N2_COLOR}fstablocal=${N0_COLOR}     - <path>: additional fstab file stored as fstab.local.
 ${N2_COLOR}interface=${N0_COLOR}      - <name>:  specify jail interface. Use 'ppt-XX' prefix (+vnet=1) to 
                   pass XX as vnet interface instead of 'epair', e.g.: 'ppt-em0'.
                   Warning! the PPT interface will disappear from the host system while the container is running.
 ${N2_COLOR}jprofile=${N0_COLOR}       - <name>:  specify jail profile for creating jail.
 ${N2_COLOR}jnameserver=${N0_COLOR}    - <IP>: override default 'jnameserver' settings for jail.
 ${N2_COLOR}zfs_snapsrc=${N0_COLOR}    - <name>: use ZFS snapshot as data source.
 ${N2_COLOR}pkg_bootstrap=${N0_COLOR}  - 0,1: overwrite pkg_bootstrap from conf file.
 ${N2_COLOR}sysdir_volume=${N0_COLOR}  - 0,1: Copy jails-system/\$jname sys dir to VOLUMES/\$jname-system
                   ( 0 - by default, do not move );
 ${N2_COLOR}removejconf=${N0_COLOR}    - 0,1: remove jconf after jcreate? 0 - don't remove.
 ${N2_COLOR}runasap=${N0_COLOR}        - 0,1: when 1 - run a jail immediately (atomic jcreate+jstart).
 ${N2_COLOR}quiet=${N0_COLOR}          - 0,1: be quiet, dont output verbose message.
 ${N2_COLOR}ver=${N0_COLOR}            - Can be: '14.4' for RELEASE, '14' for RELENG, 'auto' - inherits base version,
                   or 'empty' for empty dataset.
 ${N2_COLOR}zfs_encryption=${N0_COLOR} - 0,1: enable native ZFS encryption.


Additional args when RACCT enabled: ${RCTL} ${RCTL_EXTRA}

 ${N2_COLOR}cpu=${N0_COLOR}            - limit number of CPU cores, e.g: 1
 ${N2_COLOR}fsquota=${N0_COLOR}        - set ZFS quota, e.g: 10g
 ${N2_COLOR}vmemoryuse=${N0_COLOR}     - limit memory use, e.g: 512m


${H3_COLOR}Examples${N0_COLOR}:

 # cbsd jcreate jname=test runasap=1 zfs_encryption=1 interface=ppt-em
 # cbsd jcreate jname=test2 astart=0 pkglist=\"misc/mc net/fping\" ip4_addr=DHCP,DHCPv6 allow_sysvipc=1 allow_raw_sockets=1
 # cbsd jcreate jname=vnet1 runasap=1 ip4_addr=\"10.0.1.5/24\" ci_gw4=\"10.0.1.1\" ci_user_pubkey=\"/root/.ssh/authorized_keys\"
 # cbsd jcreate jname=deb jprofile=devuan_daedalus allow_raw_sockets=1
 # cbsd jcreate jname=rock jprofile=rocky_9 allow_raw_sockets=1
 # cbsd jcreate jname=riscv pkg_bootstrap=0 arch=riscv emulator=\"qemu-riscv64-static\" exec_start=\"/bin/qemu-riscv64-static /bin/sh /etc/rc\" exec_stop=\"/bin/qemu-riscv64-static /bin/sh /etc/rc.shutdown\"
 # cbsd jcreate jname=nictest vnet=1 interface=ppt-em0
 # cbsd jcreate jname=xx ver=14.4 vnet=1 sysrc=\"ifconfig_eth0+='mtu 1450' inetd_enable=YES\"
 # cbsd jcreate jname=vmagent from=https://dl.convectix.com/img/amd64/amd64/14.2/vmagent/vmagent.img pkg_bootstrap=0 runasap=1
 # cbsd jcreate jname=myapp from=fbbb4e8707f6794008cc6e8ed0d86082 runasap=1
 # cbsd jcreate jname=small flavor=small1 runasap=1 jnameserver=\"8.8.8.8,8.8.4.4\"
 #[*] cbsd jcreate jname=test ver=empty baserw=1 pkg_bootstrap=0 floatresolv=0 applytpl=0 etcupdate_init=0 from=docker.io/convectix/freebsd14-base
 #[*] cbsd jcreate jname=test ver=empty baserw=1 pkg_bootstrap=0 floatresolv=0 applytpl=0 etcupdate_init=0 from=docker.io/library/alpine emulator=linux
 #[*] cbsd jcreate jname=influx ip4_addr=DHCP platform=Linux from=docker.io/library/influxdb:2.7 environment=\"INFLUXD_INIT_PORT=9099\" environment=\"INFLUXD_INIT_PING_ATTEMPTS=600\" environment=\"DOCKER_INFLUXDB_INIT_MODE=setup\" environment=\"DOCKER_INFLUXDB_INIT_USERNAME=my-user\" environment=\"DOCKER_INFLUXDB_INIT_PASSWORD=my-password\" environment=\"DOCKER_INFLUXDB_INIT_ORG=my-org\" environment=\"DOCKER_INFLUXDB_INIT_BUCKET=my-bucket\" environment=\"DOCKER_INFLUXDB_INIT_RETENTION=1w\" environment=\"DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=my-super-secret-auth-token\"
 #[*] cbsd jcreate jname=influx ip4_addr=DHCP platform=Linux from=docker.io/library/influxdb:2.7 exec_start=\"influxd &\"
 #[*] cbsd jcreate jname=redis ip4_addr=DHCP platform=Linux from=docker.io/library/redis
 #[*] cbsd jcreate jname=memcached ip4_addr=DHCP platform=Linux from=docker.io/library/memcached environment=\"MEMCACHED_MEMORY_LIMIT=512m\" exec_start=\"memcached -u root &\"

# VLAN tagging for jail vnet bridge members examples:

Pre-configuration:

  ifconfig bridge0 create vlanfilter up
  ifconifg bridge0 addm em0 untagged 1 tagged 2,3

Usage examples:

  cbsd jcreate jname=test1 vnet=1 inteface=bridge0 nic_vlan_untagged=1
  cbsd jcreate jname=test1 vnet=1 inteface=bridge0 nic_vlan_tagged=2,3
  cbsd jcreate jname=test1 vnet=1 inteface=bridge0 nic_flags=private
  cbsd jcreate jname=test1 vnet=1 inteface=bridge0 nic_mtu=1500

# Nice example HOW TO create micro-jail (~8MB, 'busybox' like) with SSH root access:

 # cbsd jcreate jname=micro1 baserw=1 ver=empty applytpl=0
 # cbsd copy-binlib basedir=/ chaselibs=1 dstdir=/usr/jails/jails-data/micro1-data filelist=${CIX_DISTDIR}/share/FreeBSD-microjail.txt.xz
 # cbsd sysrc jname=micro1 sshd_flags=\"-oUseDNS=no -oPermitRootLogin=yes\" sshd_enable=YES
 # cp -a /etc/ssh /usr/jails/jails-data/micro1-data/etc/
 # cp -a /etc/gss /usr/jails/jails-data/micro1-data/etc/
 # cp -a /etc/pam.d /usr/jails/jails-data/micro1-data/etc/
 # mkdir -p /usr/jails/jails-data/micro1-data/var/empty /usr/jails/jails-data/micro1-data/var/log /usr/jails/jails-data/micro1-data/var/run /usr/jails/jails-data/micro1-data/root /usr/jails/jails-data/micro1-data/dev
 # chmod 0700 /usr/jails/jails-data/micro1-data/var/empty
 # pw -R /usr/jails/jails-data/micro1-data usermod root -s /bin/sh

${H3_COLOR}See also${N0_COLOR}:

 cbsd jconstruct --help
 cbsd jconstruct-tui --help
 cbsd up --help
 cbsd images --help
 cbsd jset --help
 cbsd makeresolv --help
 cbsd vhidcfg --help
 cbsd vhidcfg-tui --help

"
CBSDMODULE="jail"
EXTHELP="wf_jcreate"

. ${subrdir}/nc.subr
. ${system}
. ${tools}
. ${mdtools}
. ${jfs}

ci_user_pubkey=
sysrc=
from=
flavor=
oflavor=
ver=
over=
oplatform=
oenvironment=
environment=

# hack to avoid conflict with global jnameserver
ojnameserver="${jnameserver}"
export CIX_INIT_SAVE2FILE="new"
export CIX_INIT_SKIP="environment"		# multiple: environment=X environment=Y we process separately as $CIX_OTHER_ARGS
cixinit

if [ -z "${jconf}" ]; then
	jconf="${CIX_INIT_CONF}"
	: "${removejconf:=1}"
fi

[ -z "${jconf}" -a -z "${jname}" ] && err 1 "${N1_COLOR}please set for jcreate: ${N2_COLOR}${jconf}${N0_COLOR}"

# hack to avoid conflict with global jnameserver
if [ "${ojnameserver}" = "${jnameserver}" ]; then
	# no jnameserver args: inherits jnameserver by default
	jnameserver="0"
	ojnameserver="0"
else
	ojnameserver="${jnameserver}"
fi

# jcreate global conf
readconf jcreate.conf

quiet="${oquiet:-$quiet}"
: "${quiet:=0}"

jnameserver="${ojnameserver:-$jnameserver}"
: "${autorestart:=0}"

mkfstab()
{
	local _dir=

	# dirname ${mount_fstab}
	_dir="${mount_fstab%/*}"

	[ ! -d "${_dir}" ] && ${MKDIR_CMD} -p "${_dir}"

	${CAT_CMD} > ${mount_fstab} <<________EOF
# Please do not edit this file for additional fstabs
# Use ${mount_fstab}.local instead
________EOF

	if [ ${baserw} -eq 0 ]; then
		${CAT_CMD} >> ${mount_fstab} <<________________EOF
${data}/etc /etc ${NULLFS} rw 0 0
${data}/root /root ${NULLFS} rw 0 0
${data}/tmp /tmp ${NULLFS} rw 0 0
${data}/home /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

		if [ "${platform}" = "DragonFly" ]; then
			# DFLY use OBJDIR=/usr/obj by default (which we can't overwrite via /etc/make.conf for some reason?)
			${CAT_CMD} >> ${mount_fstab} <<________________________EOF
${data}/usr/obj /usr/obj ${NULLFS} rw 0 0
________________________EOF
		fi
	fi

	${TOUCH_CMD} ${mount_fstab}.local
}

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

	# shellcheck disable=SC2016
	# $1 is expanded by awk
	#module=$( cbsdsqlro "" "SELECT helpername FROM system ORDER BY helpername ASC" | ${AWK_CMD} '{printf $1}' )

	cbsdsqlro_vars "${_srcfile}" "SELECT helpername FROM system LIMIT 1" module

	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Install and apply helpers ${_srcfile}: ${N2_COLOR}${module}${N0_COLOR}"

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

	[ ! -d "${helperdir}" ] && ${MKDIR_CMD} -p ${helperdir}

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

	[ ${quiet} -ne 1 ] && echo ":: ${CP_CMD} -a ${_srcfile} ${formfile}"
	${CP_CMD} -a ${_srcfile} ${formfile}

	[ ${quiet} -ne 1 ] && echo ":: forms module=${module} mode=apply jname=${jname} inter=0"
	forms module=${module} mode=apply jname=${jname} inter=0
}

### MAIN
# map flavor
flavor="${ooflavor:-$flavor}"

if [ -n "${flavor}" ]; then
	unset ocpu cpu ovmemoryuse vmemoryuse ofsquota fsquota
	flavors_available=$( cbsdsqlro ${dbdir}/local.sqlite "SELECT name FROM vmpackages ORDER BY name ASC" | ${XARGS_CMD} )
	flavor_exist=0
	for i in ${flavors_available}; do
		[ "${flavor}" = "${i}" ] && flavor_exist=1 && break
	done

	[ ${flavor_exist} -eq 0 ] && log_err 1 "${N1_COLOR}${CIX_APP}: no such flavor [${flavor}], available flavors: ${N2_COLOR}${flavors_available}${N0_COLOR}"

	_res=$( cbsdsqlro ${dbdir}/local.sqlite "SELECT pkg_vm_cpus,pkg_vm_ram,pkg_vm_disk FROM vmpackages WHERE name='${flavor}' LIMIT 1" 2>/dev/null )

	[ -z "${_res}" ] && log_err 1 "${N1_COLOR}${CIX_APP}: unable to get vm_cpus/vm_ram/imgsize for flavor: ${N2_COLOR}${flavor}${N0_COLOR}"
	sqllistdelimer="|"

	sqllist "${_res}" ocpu ovmemoryuse ofsquota
	unset sqllistdelimer
	${ECHO} "${N1_COLOR}${CIX_APP}: flavor ${flavor} -> cpu/vmemoryusem/fsquota: ${N2_COLOR}[${_res}]${N0_COLOR}"

	[ -z "${ovmemoryuse}" ] && log_err 1 "${N1_COLOR}${CIX_APP}: unable to get 'vmemoryuse' for flavor: ${N2_COLOR}${flavor}${N0_COLOR}"
	[ -z "${ofsquota}" ] && log_err 1 "${N1_COLOR}${CIX_APP}: unable to get 'fsquota' for flavor: ${N2_COLOR}${flavor}${N0_COLOR}"
	[ -z "${ocpu}" ] && log_err 1 "${N1_COLOR}${CIX_APP}: unable to get 'cpu' for flavor: ${N2_COLOR}${flavor}${N0_COLOR}"

	cpu="${ocpu}"
	vmemoryuse="${ovmemoryuse}"
	fsquota="${ofsquota}"

	unset flavor oflavor flavor_exist flavors_available _res
fi

. ${subrdir}/time.subr
gettime st_time

[ -n "${delpkglist}" ] && odelpkglist="${delpkglist}"
# push pkg_bootstrap to orig_ variable
[ -n "${pkg_bootstrap}" ] && opkg_bootstrap="${pkg_bootstrap}"

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

readconf zfs.conf
readconf buildworld.conf

[ -n "${ver}" ] && over="${ver}"

readconf jail-freebsd-default.conf

# several defaults
[ -z "${mnt_start}" ] && mnt_start="0"
[ -z "${mnt_stop}" ] && mnt_stop="0"
[ -z "${etcupdate_init}" ] && etcupdate_init="1"

# set default nice from rctl_nice
[ -n "${rctl_nice}" ] && nice="${rctl_nice}"

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

[ ! -f "${jconf}" ] && err 1 "${N1_COLOR}no such jconf file${N0_COLOR}"

capture jconf ${REALPATH_CMD} ${jconf}

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

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

# TRIM DOS CRLF
#${CAT_CMD} ${jconf} | ${TR_CMD} -d \\r > ${temprcconf}
#${CAT_CMD} ${temprcconf} >${jconf}
${CP_CMD} ${jconf} ${temprcconf}

removejconf="${oremovejconf:-$removejconf}"

if [ "${removejconf}" = "1" ]; then
	# shellcheck disable=SC2064
	# we need expansion right now
	trap "${RM_CMD} -f ${temprcconf} ${jconf}" HUP INT ABRT BUS TERM EXIT
else
	# shellcheck disable=SC2064
	trap "${RM_CMD} -f ${temprcconf}" HUP INT ABRT BUS TERM EXIT
fi

## environment manage
xenvironment=
for i in ${CIX_OTHER_ARGS}; do
	strpos --str="${i}" --search="="
	_pos=$?

	if [ ${_pos} -ne 0 ]; then
		_arg_len=$( strlen ${i} )
		_pref=$(( _arg_len - _pos ))
		capture ARG substr --pos=0 --len=${_pos} --str="${i}"

		case "${ARG}" in
			environment)
				VAL=$( substr --pos=$(( _pos + 2 )) --len=${_pref} --str="${i}" | ${TR_CMD} -d '"' )
				if [ -z "${xenvironment}" ]; then
					xenvironment="${VAL}"
				else
					xenvironment="${xenvironment} ${VAL}"
					fi
				;;
		esac
		shift
		continue
	fi
done

# todo: when 'from' exist: use temprcconf settings to jset fromfile to re-configure default image options

[ -n "${ofrom}" ] && from="${ofrom}"

# todo: there is a lot of duplicate code (for example, create_fs/from_zfssnap): cleaning required.
if [ -n "${from}" ]; then
	. "${temprcconf}"
	jstatus jname="${jname}" > /dev/null 2>&1 || stderr 1 "${N1_COLOR}${CIX_APP}: jail already exist: ${N2_COLOR}${jname}${N0_COLOR}"
	[ ! -r ${dbdir}/images.sqlite ] && ${miscdir}/updatesql ${dbdir}/images.sqlite ${CIX_DISTDIR}/share/local-images.schema images

	from_md5=

	# is from=MD5?
	cbsdsqlro_vars images "SELECT md5 FROM images WHERE md5='${from}'" _res
	if [ -n "${_res}" ]; then
		from_md5="${from}"
	else
		# second chance - is md5(from) exist?
		if [ -z "${_res}" ]; then
			capture tmpfrom ${miscdir}/cbsd_md5 "${from}"
			cbsdsqlro_vars images "SELECT md5 FROM images WHERE md5='${tmpfrom}'" _res
			[ -n "${_res}" ] && from_md5="${tmpfrom}"
			unset tmpfrom
		fi
	fi

	jail_created=0

#	if [ ! -d "{workdir}/basejail/${from_md5}" ]; then
#		images mode=remove md5=${from_md5} || true
#		from_md5=
#	fi

	if [ -z "${from_md5}" ]; then
		# cbsd image register ...
		[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}${CIX_APP}: image not exist, call 'images mode=register': ${N2_COLOR}${from}${N0_COLOR}"
		if [ "${emulator}" != "jail" ]; then
			images mode=register path="${from}" platform="${emulator}"
			ret=$?
		else
			[ -n "${oplatform}" ] && platform="${oplatform}"
			images mode=register path="${from}" platform="${platform}"
			ret=$?
		fi
		ret=$?
		if [ ${ret} -ne 0 ]; then
			stderr 1 "${N1_COLOR}${CIX_APP}: images failed (${ret}: cbsd images mode=register from=\"${N2_COLOR}${from}${N1_COLOR}\"${N0_COLOR}"
		fi
		capture tmpfrom ${miscdir}/cbsd_md5 "${from}"
		cbsdsqlro_vars images "SELECT md5 FROM images WHERE md5='${tmpfrom}'" _res
		[ -z "${_res}" ] && stderr 1 "${N1_COLOR}${CIX_APP}: images failed: cbsd images mode=register from=\"${N2_COLOR}${from}${N1_COLOR}\"${N0_COLOR}"
		from_md5="${tmpfrom}"
		unset tmpfrom
	fi

	# first of all: check zfs dataset existance for image
	if [ ${zfsfeat} -eq 1 ]; then
		. ${subrdir}/zfs.subr
		capture DATA ${ZFS_CMD} get -Ho value name ${jaildatadir}
		_zfssrc="${DATA}/${from_md5}"
		_zfssrc_snap="${DATA}/${from_md5}@start"

		${ZFS_CMD} list -t snapshot ${_zfsssrc_snap} > /dev/null 2>&1
		_ret=$?
		if [ ${_ret} -ne 0 ]; then
			[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}${CIX_APP}: create snapshot: ${N2_COLOR}${_zfssrc}@start${N0_COLOR}"
			${ZFS_CMD} snapshot ${_zfssrc}@start
			${ZFS_CMD} list -t snapshot ${_zfssrc_snap} > /dev/null 2>&1
			_ret=$?
			[ ${_ret} -ne 0 ] && stderr 1 "${N1_COLOR}${CIX_APP}: unable to create snapshot: ${N2_COLOR}${ZFS_CMD} list -t snapshot ${_zfssrc_snap}${N0_COLOR}"
		else
			[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}${CIX_APP}: create snapshot: ${N2_COLOR}${_zfssrc}@start${N0_COLOR}"
		fi

		[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}create jail from image snapshot: ${N2_COLOR}${_zfssrc_snap}${N0_COLOR}" 1>&2
		echo "jcreate jname="${jname}" zfs_snapsrc="${_zfssrc_snap}" ver=empty baserw=1 pkg_bootstrap=0 floatresolv=0 applytpl=0 etcupdate_init=0"
		[ -n "${oplatform}" ] && platform="${oplatform}"
		jcreate jname="${jname}" zfs_snapsrc="${_zfssrc_snap}" ver=empty baserw=1 pkg_bootstrap=0 floatresolv=0 applytpl=0 etcupdate_init=0 platform="${platform}" emulator="${emulator}"
		jail_created=1
	else
		[ ! -d "${workdir}/basejail/${from_md5}" ] && err 1 "${N1_COLOR}${CIX_APP}: no such resources: ${from_md5}: ${N2_COLOR}${workdir}/basejail/${from_md5}${N0_COLOR}"
		[ -n "${oplatform}" ] && platform="${oplatform}"
		jcreate jname="${jname}" baserw=1 pkg_bootstrap=0 ver=empty etcupdate_init=0 floatresolv=0 applytpl=0 platform="${platform}" emulator="${emulator}"
		. ${subrdir}/rcconf.subr
		[ $? -eq 1 ] && err 1 "${N1_COLOR}${CIX_APP}: unable to create jail ${jname} from: ${N2_COLOR}${from}${N0_COLOR}"
		if [ ! "${data}" ]; then
			jremove jname="${jname}" > /dev/null 2>&1 || true
			err 1 "${N1_COLOR}${CIX_APP}: no such data directory: ${N2_COLOR}${data}${N0_COLOR}"
		fi
		${RSYNC_CMD} -a --hard-links --links --acls --xattrs --numeric-ids --recursive --partial --delete ${workdir}/basejail/${from_md5}/ ${data}/
	fi

	#check for jail exist
	jstatus jname=${jname} > /dev/null 2>&1
	[ $? -ne 1 ] && err 1 "${N1_COLOR}${CIX_APP}: unable to create jail ${jname} from: ${N2_COLOR}${from}${N0_COLOR}"

	. ${temprcconf}

	if [ -n "${from_md5}" -a -n "${BUILDAH_CMD}" ]; then
		${BUILDAH_CMD} --root ${workdir}/basejail/buildah images -n | while read _path _tag _image_id _rest; do
			_md5_ver=$(${miscdir}/cbsd_md5 "${_path}:${_tag}")
			_md5_nover=$(${miscdir}/cbsd_md5 "${_path}")
			if [ "${from_md5}" = "${_md5_ver}" -o "${from_md5}" = "${_md5_nover}" ]; then
				oci_dir="${workdir}/jails-system/${jname}/oci"
				${MKDIR_CMD} -p ${oci_dir}
				oci_config="${oci_dir}/v1.config"
				${BUILDAH_CMD} --root ${workdir}/basejail/buildah inspect ${_image_id} | ${JQ_CMD} -r .OCIv1.config > ${oci_config}
				${JQ_CMD} -r '(.Env // [])[]' < ${oci_config} > ${workdir}/jails-system/${jname}/environment
				[ -z "${oexec_start}" ] && exec_start="0"  # do not use default exec_start
				jset jname=${jname} emulator_flags="ocijail" ver=empty exec_start="${exec_start}"
			fi
		done
	fi

	#echo "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin" > ${jailsysdir}/${jname}/environment
	if [ -n "${xenvironment}" ]; then
		# save env
		for i in ${xenvironment}; do
			echo "${i}" >> ${jailsysdir}/${jname}/environment
		done
	fi

	for i in ${MYOPTARG}; do
		eval T="\$o${i}"

		case "${i}" in
			jname|from|removejconf)
				continue
				;;
			interface)
				[ -n "${T}" ] && jset jname=${jname} ${i}="${T}"
				[ -n "${T}" ] && jailnic ${jname} update eth0 ${i##nic_}="${T}"
				;;
			nic_*)
				[ -n "${T}" ] && jailnic ${jname} update eth0 ${i##nic_}="${T}"
				;;
			*)
				[ -n "${T}" ] && jset jname=${jname} ${i}="${T}"
				;;
		esac
	done

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

	exit 0
fi

. ${temprcconf}

[ -z "${jname}" ] && err 1 "${N1_COLOR}No such jname variable${N0_COLOR}"

# Redis
if [ "${mod_cbsd_redis_enabled}" = "YES" -a -z "${MOD_CBSD_REDIS_DISABLED}" ]; then
	cbsdredis publish cbsd_events '{"cmd":"jcreate", "node":"'${nodename}'", "jail":"'${jname}'", "status":1, "ip4_addr":"'${ip4_addr}'"}'
fi

# CBSD QUEUE
if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
	[ -n "${cbsd_jail_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_jail_queue_name} id=${jname} cmd=jcreate ip4_addr=${ip4_addr} protected=${protected} vnc_port=0 status=1
fi

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

# TODO: merge
if [ -n "${jprofile}" ]; then
	if [ -r "${etcdir}/jail-freebsd-${jprofile}.conf" ]; then
		${ECHO} "${N1_COLOR}Use profile: ${N2_COLOR}${etcdir}/jail-freebsd-${jprofile}.conf${N0_COLOR}"
		${CAT_CMD} ${etcdir}/jail-freebsd-${jprofile}.conf >> ${temprcconf}
	elif [ -r "${etcdir}/defaults/jail-freebsd-${jprofile}.conf" ]; then
		${ECHO} "${N1_COLOR}Use profile: ${N2_COLOR}${etcdir}/defaults/jail-freebsd-${jprofile}.conf${N0_COLOR}"
		${CAT_CMD} ${etcdir}/defaults/jail-freebsd-${jprofile}.conf >> ${temprcconf}
	fi
fi

. ${temprcconf}

[ -n "${over}" ] && ver="${over}"
[ -n "${ojnameserver}" -a "${ojnameserver}" != "0" ] && jnameserver="${ojnameserver}"

# map 'native' to ver/arch
. ${subrdir}/build.subr

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

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

# append sysrc
SYSRC_TEMPRCCONF=

# apply pkglist from tpl_pkglist
if [ -n "${tpl_pkglist}" ]; then
	SYSRC_TEMPRCCONF="${SYSRC_TEMPRCCONF} pkglist=\"${tpl_pkglist}\""
	pkglist="${tpl_pkglist}"
fi

init_jail_path
init_target_arch

if [ -n "${basename}" ]; then
	init_basedir -b ${basename}
	_basename_args="-b ${basename}"
else
	init_basedir
	_basename_args=
fi

init_kerneldir

if ! jstatus jname="${jname}" > /dev/null 2>&1; then
	# Redis
	if [ "${mod_cbsd_redis_enabled}" = "YES" -a -z "${MOD_CBSD_REDIS_DISABLED}" ]; then
		cbsdredis publish cbsd_events '{"cmd":"jcreate", "node":"'${nodename}'", "jail":"'${jname}'", "status":2, "ip4_addr":"'${ip4_addr}'"}'
	fi

	[ ${autorestart} -eq 0 ] && err 1 "${N1_COLOR}jail ${jname} already exist, use autorestart=1 for updating via jset${N0_COLOR}"
	jset jname=${jname} jconf=${jconf} autorestart=1

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_jail_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_jail_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"
		;;
	qemu-ppc64-static)
		arch="powerpc"
		target_arch="powerpc64"
		;;
	qemu-riscv64-static)
		arch="riscv"
		target_arch="riscv64"
esac

get_base -v ${ver} ${_basename_args}
ret=$?
if [ ${ret} -ne 0 ]; then
	err 1 "${W1_COLOR}${CIX_APP}: get_base error${N0_COLOR}"
fi

[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Please wait: ${N2_COLOR}this will take a while...${N0_COLOR}"

[ -d "${data}" ] && remove_data_dir ${data}
[ ! -d ${path} -a "${baserw}" -eq 0 ] && ${MKDIR_CMD} -m 0755 -p ${path}

[ -n "${osysdir_volume}" ] && sysdir_volume="${osysdir_volume}"
[ -d "${jailsysdir}/${jname}" ] && ${RM_CMD} -rf ${jailsysdir}/${jname}		# this should never happen

if [ "${sysdir_volume}" = "1" ]; then
	_volsysdir="${workdir}/VOLUMES/${jname}-system"
	if [ -d "${_volsysdir}" ]; then
		${ECHO} "${N1_COLOR}${CIX_APP}: sysdir_volume=1, link to an existing system directory: ${N2_COLOR}${_volsysdir}${N0_COLOR}" 1>&2
		${LN_CMD} -s "${_volsysdir}" ${jailsysdir}/${jname}
	else
		${ECHO} "${N1_COLOR}${CIX_APP}: sysdir_volume=1, create system directory: ${N2_COLOR}${_volsysdir}${N0_COLOR}" 1>&2
		${MKDIR_CMD} -p ${_volsysdir}
		${LN_CMD} -s "${_volsysdir}" ${jailsysdir}/${jname}
	fi
fi

##
[ ! -d ${jailsysdir}/${jname}/traffic ] && ${MKDIR_CMD} -p ${jailsysdir}/${jname}/traffic
${TOUCH_CMD} ${jailsysdir}/${jname}/descr

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

if [ "${mnt_start}" != "0" ]; then
	if [ ! -r "${mnt_start}" -o ! -x "${mnt_start}" ]; then
		err 1 "mnt_start script not exist or not executable: ${mnt_start}"
	fi
	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Execute mnt_start script: ${N2_COLOR}${mnt_start}${N0_COLOR}..."
	# external mount, reset zfsfeat
	zfsfeat=0
	[ ! -d "${data}" ] && ${MKDIR_CMD} ${data}
	[ ! -d ${jailfstabdir}/${jname} ] && ${MKDIR_CMD} -p ${jailfstabdir}/${jname}
	[ ! -d ${jailsysdir}/${jname} ] && ${MKDIR_CMD} -p ${jailsysdir}/${jname}
	${mnt_start} -d ${data} -f ${jailfstabdir}/${jname} -j ${jname} -r ${jailrcconfdir} -s ${jailsysdir}/${jname}
	_ret=$?
	if [ ${_ret} -ne 0 ]; then
		err 1 "${W1_COLOR}error: ${N1_COLOR}mnt_start script failed: ${N2_COLOR}${mnt_start} -d ${data} -f ${jailfstabdir} -j ${jname} -r ${jailrcconfdir} -s ${jailsysdir}/${jname}${N0_COLOR}"
	fi
	create_fs "${data}" || err 1 "${N1_COLOR}create_fs failed${N0_COLOR}"
else
	create_fs "${data}" || err 1 "${N1_COLOR}create_fs failed${N0_COLOR}"
fi

[ ! -d "${data}" ] && err 1 "Can't create datadir ${data}"

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

if [ -d "${jailsysskeldir}" ]; then
	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}${CIX_APP}: copy system skel from: ${N2_COLOR}${jailsysskeldir}${N0_COLOR}"
	# we have custom skeldir. copy
	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Applying custom skel system dir template from: ${N2_COLOR}${jailsysskeldir}${N0_COLOR}"
	${RSYNC_CMD} -a ${jailsysskeldir}/ ${jailsysdir}/${jname}/
	# local fstab ?
	[ -f "${jailsysskeldir}/fstab.local" ] && fstablocal="${jailsysskeldir}/fstab.local"
else
	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}${CIX_APP}: system skel dir not found: ${N2_COLOR}${jailsysskeldir}${N0_COLOR}"
fi

system_dir="clone-local.d \
clone.d \
create.d \
facts.d \
master_create.d \
master_poststart.d \
master_poststop.d \
master_prestart.d \
master_prestop.d \
remove.d \
rename.d \
start.d \
stop.d"

for i in ${system_dir}; do
	if [ ! -d "${jailsysdir}/${jname}/${i}" ]; then
		${MKDIR_CMD} -m 0775 -p ${jailsysdir}/${jname}/${i}
	fi
	${CHOWN_CMD} -R ${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"
	${TOUCH_CMD} "${mdimage}"
	# Linux does not support postfix in bs=, e.g. bs=1m
	case "${platform}" in
		Linux)
			${DD_CMD} if="/dev/zero" of="${mdimage}" bs=1000000 count=0 seek=${blockcount} 1> /dev/null 2>&1 || err 1 "jcreate error: couldn't create the image file. ${mdimage}"
			;;
		*)
			${DD_CMD} 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}"
			;;
	esac
	# Attach the .img file as a memory disk.
	mdimagedevice=$( ${MDCONFIG_CMD} -a -t vnode -f "${mdimage}" ) \
	|| err 1 "Error: Failed to mdconfig on ${mdimage}"
	${NEWFS_CMD} -j -n -U "/dev/${mdimagedevice}" 1> /dev/null 2>&1 || ${MDCONFIG_CMD} -d -u "${mdimagedevice}" || err 1 "Error: Couldn't newfs the memory disk. ${mdimagedevice}"
	${MDCONFIG_CMD} -d -u "${mdimagedevice}"
	# mount here
	mountmd jroot=${data} mdfile=${mdimage}
fi
## MD backend

if [ -z "${zfs_snapsrc}" ]; then
	case "${platform}" in
		Linux)
			true
			;;
		*)
			[ "${ver}" != "empty" ] && populate_freebsd_world
			;;
	esac
fi

# don't inherit /var/db/pkg for base-in-pkg in baserw=0:
if [ "${ver}" != "empty" ]; then
	if [ ${baserw} -ne 1 -a -d "${BASE_DIR}/var/db/pkg" ]; then
		[ -d "${data}/var/db/pkg" ] && ${RM_CMD} -rf "${data}/var/db/pkg"
		[ ! -d "${data}/var/db" ] && ${MKDIR_CMD} -m 0755 -p ${data}/var/db
	elif [ ${baserw} -eq 1 -a -d "${data}/var/db" ]; then
		# Let's delete the 'pkg' entry, as this may prevent the pkg from being (re-)installed correctly
		# (there are no files in the /usr/local)
		if [ -r ${data}/var/db/local.sqlite ]; then
			cbsdsqlrw ${data}/var/db/local.sqlite "DELETE FROM packages WHERE name='pkg' OR name='pkg-devel'"
		fi
	fi
fi

customskel
mkfstab

case "${ip4_addr}" in
	[Dd][Hh][Cc][Pp])
		capture ip4_addr dhcpd
		[ $? -eq 2 ] && log_err 1 "${W1_COLOR}${CIX_APP} error: ${N1_COLOR}${jname}: no free IP address for DHCP in 'nodeippool', please check: ${N2_COLOR}cbsd initenv-tui${N0_COLOR}"
		SYSRC_TEMPRCCONF="${SYSRC_TEMPRCCONF} ip4_addr=\"${ip4_addr}\""
		# CBSD QUEUE
		if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
			[ -n "${cbsd_jail_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_jail_queue_name} id=${jname} cmd=update ip4_addr=${ip4_addr} vnc_port=0 status=1
		fi
		;;
	[Dd][Hh][Cc][Pp][vV]6)
		capture ip4_addr dhcpdv6
		[ $? -eq 2 ] && log_err 1 "${W1_COLOR}${CIX_APP} error: ${N1_COLOR}${jname}: no free IP address for DHCPv6 in 'nodeip6pool', please check: ${N2_COLOR}cbsd initenv-tui${N0_COLOR}"
		SYSRC_TEMPRCCONF="${SYSRC_TEMPRCCONF} ip4_addr=\"${ip4_addr}\""
		# CBSD QUEUE
		if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
			[ -n "${cbsd_jail_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_jail_queue_name} id=${jname} cmd=update ip4_addr=${ip4_addr} vnc_port=0 status=1
		fi
		;;
esac

updateconf ${temprcconf} \
	arch="${arch}" \
	ver="${ver}" \
	stable="${stable}" \
	path="${path}" \
	mount_fstab="${mount_fstab}" \
	rcconf="${rcconf}" \
	data="${data}" \
	jnameserver="${jnameserver}" ${SYSRC_TEMPRCCONF}

#${CP_CMD} ${temprcconf} ${rcconf}
${MV_CMD} ${temprcconf} ${rcconf}

if [ -n "${fstablocal}" ]; then
	# relativepath?
	capture prefix substr --pos=0 --len=1 --str="${fstablocal}"
	if [ "${prefix}" != "/" ]; then
		capture fstablocal ${REALPATH_CMD} "${CIX_PWD}/${fstablocal}"
	else
		capture fstablocal ${REALPATH_CMD} "${fstablocal}"
	fi
	if [ -r "${fstablocal}" ]; then
		[ ! -d ${jailfstabdir}/${jname} ] && ${MKDIR_CMD} ${jailfstabdir}/${jname}
		${CP_CMD} ${fstablocal} ${jailfstabdir}/${jname}/fstab.local
	else
		err 1 "${W1_COLOR}Warning: fstablocal set but file not accesible: ${N2_COLOR}${fstablocal}${N0_COLOR}"
	fi
fi

#echo "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin" > ${jailsysdir}/${jname}/environment
if [ -n "${xenvironment}" ]; then
	# save env
	for i in ${xenvironment}; do
		echo "${i}" >> ${jailsysdir}/${jname}/environment
	done
fi

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

if [ ${res} -ne 0 ]; then
	[ ${quiet} -ne 1 ] && ${ECHO} 1>&2
	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Creating ${jname} failed: ${N2_COLOR}cbsd jregister${N0_COLOR}" 1>&2
	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Please review bad config file: ${N2_COLOR}/tmp/rc.conf_${jname}${N0_COLOR}" 1>&2
	${MV_CMD} ${rcconf} /tmp
	#cleanup
	[ -f "${mount_fstab}" ] && ${RM_CMD} -f ${mount_fstab}
	remove_data_dir ${data}
	exit 1
fi

SQL_JAIL_BULK=
cbsdsqlrw local "UPDATE jails SET state_time='${st_time}' WHERE jname='${jname}'"

# cached sqlite3
if [ ! -r "${tmpdir}/jail-local.sqlite" ]; then
	jsqlite-cache-create file=${tmpdir}/jail-local.sqlite
	_ret=$?
	[ ${_ret} -ne 0 ] && err 1 "${W1_COLOR}${CIX_APP} error: ${N2_COLOR}jsqlite-cache-create file=${tmpdir}/jail-local.sqlite${N0_COLOR}"
fi
${CP_CMD} -a ${tmpdir}/jail-local.sqlite ${jailsysdir}/${jname}/local.sqlite

if [ -n "${jailnic_temp_sql}" ]; then
	[ ! -r "${jailnic_temp_sql}" ] && err 1 "${N1_COLOR}${CIX_APP}: jailnic_temp_sql file not readable: ${N2_COLOR}${jailnic_temp_sql}${N0_COLOR}"

	# dump and import jailnic table
	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}${CIX_APP}: import jailnic data from: ${N2_COLOR}${jailnic_temp_sql} ${N1_COLOR}via${N2_COLOR} ${_tmp_table_file}${N1_COLOR} dump${N0_COLOR}"
	cbsdsqlrw "${jailsysdir}/${jname}/local.sqlite" "DELETE FROM jailnic"
	${SQLITE3_CMD} "${jailnic_temp_sql}" ".mode insert jailnic" "SELECT * FROM jailnic;" | ${SQLITE3_CMD} "${jailsysdir}/${jname}/local.sqlite"
	${RM_CMD} -f ${jailnic_temp_sql} ${jailnic_temp_sql}-shm ${jailnic_temp_sql}-wal
else
	tmp_type=${interface%%-*}		# cut all after '#'
	tmp_iface=${interface##*-}		# cut all before '#'

	case "${tmp_type}" in
		ppt|epair|ovs)
			SQL_JAIL_BULK="${SQL_JAIL_BULK}; INSERT INTO jailnic ( name,nic_order,nic_slot,nic_parent,nic_mtu,nic_flags,nic_vlan_untagged,nic_vlan_tagged ) VALUES ( '${tmp_iface}','0','0','auto','0','0','0','0' )"
			;;
		*)
			SQL_JAIL_BULK="${SQL_JAIL_BULK}; INSERT INTO jailnic ( name,nic_order,nic_slot,nic_parent,nic_mtu,nic_flags,nic_vlan_untagged,nic_vlan_tagged ) VALUES ( 'eth0','0','0','auto','0','0','0','0' )"
			;;
	esac

	unset tmp_iface= tmp_type=

	if [ ${vnet} -eq 1 ]; then
		SQL_JAIL_BULK="${SQL_JAIL_BULK}; UPDATE jailnic SET nic_parent='${interface}'"
	fi
fi

# rctl
. ${distsharedir}/rctl.conf

for i in ${RCTL} ${RCTL_EXTRA}; do
	_val=
	eval _val="\$${i}"
	[ -z "${_val}" ] && continue
	#echo "INIT RCTL: jrctl jname=${jname} mode=set ${i}=${_val}"
	${miscdir}/daemonize ${jailctldir}/jrctl jname=${jname} mode=set ${i}=${_val} > /dev/null 2>&1
done

# Apply NIC parameters from command line
if [ -n "${nic_hwaddr}" ]; then
	SQL_JAIL_BULK="${SQL_JAIL_BULK}; UPDATE jailnic SET nic_hwaddr='${nic_hwaddr}'"
fi
if [ -n "${nic_mtu}" -a "${nic_mtu}" != "0" ]; then
	SQL_JAIL_BULK="${SQL_JAIL_BULK}; UPDATE jailnic SET nic_mtu='${nic_mtu}'"
fi
if [ -n "${nic_flags}" -a "${nic_flags}" != "0" ]; then
	SQL_JAIL_BULK="${SQL_JAIL_BULK}; UPDATE jailnic SET nic_flags='${nic_flags}'"
fi
if [ -n "${nic_vlan_untagged}" -a "${nic_vlan_untagged}" != "0" ]; then
	cbsdsqlrw ${jailsysdir}/${jname}/local.sqlite "UPDATE jailnic SET nic_vlan_untagged='${nic_vlan_untagged}'"
	SQL_JAIL_BULK="${SQL_JAIL_BULK}; UPDATE jailnic SET nic_vlan_untagged='${nic_vlan_untagged}'"
fi
if [ -n "${nic_vlan_tagged}" -a "${nic_vlan_tagged}" != "0" ]; then
	SQL_JAIL_BULK="${SQL_JAIL_BULK}; UPDATE jailnic SET nic_vlan_tagged='${nic_vlan_tagged}'"
fi

# pubkey ?
if [ -n "${ci_user_pubkey}" ]; then
	# empty/linux jail test?
	${ECHO} "${N1_COLOR}${CIX_APP}pubkey exist, enable service: ${N2_COLOR}sshd${N0_COLOR}" 2>&1
	${ECHO} "${N1_COLOR}${CIX_APP}pubkey exist, adjust via jail rc.conf: ${N2_COLOR}PermitRootLogin=without-password${N0_COLOR}" 2>&1
	${CIX_DISTDIR}/misc/cbsdsysrc -qf ${data}/etc/rc.conf sshd_flags+=" -oPermitRootLogin=without-password" sshd_enable=YES > /dev/null 2>&1
	. ${subrdir}/settings-tui-virtual.subr  # for is_valid_ssh_key
	[ "${ci_user_pubkey}" = "authorized_keys" ] && ci_user_pubkey="${workdir}/.ssh/id_rsa.pub"
	# check for injection/strip..
	prefix=$( substr --pos=0 --len=1 --str="${ci_user_pubkey}" )
	# todo: check on ealry stage?
	if [ "${prefix}" = "/" ]; then
		# its full/realpath to file
		if [ -r "${ci_user_pubkey}" ]; then
			_keytest=$( ${GREP_CMD} -v '#' ${ci_user_pubkey} | ${GREP_CMD} . | ${HEAD_CMD} -n1 )
			if ! is_valid_ssh_key "${_keytest}"; then
				jdestroy jname=${jname} || true
				${ECHO} "${N1_COLOR}${CIX_APP}: cloudinit: invalid ssh key from ${ci_user_pubkey} file. valid key: ssh-rsa,ssh-ed25519,ecdsa-*,ssh-dsa${N0_COLOR}"
				err 1 "${N1_COLOR}found: [${N2_COLOR}${_keytest}${N1_COLOR}]${N0_COLOR}"
			fi
		else
			jdestroy jname=${jname} || true
			err 1 "${N1_COLOR}${CIX_APP}: cloudinit: keyfile not found: ${N2_COLOR}${ci_user_pubkey}${N0_COLOR}"
		fi
	else
		# its relative path or pubkey string itself.
		if ! strpos --str="${ci_user_pubkey}" --search=" "; then
			# not path, check syntax
			if ! is_valid_ssh_key "${ci_user_pubkey}"; then
				jdestroy jname=${jname} || true
				err 1 "${N1_COLOR}${CIX_APP}: cloudinit: invalid ssh key: [${ci_user_pubkey}]. valid key: ssh-rsa,ssh-ed25519,ecdsa-*,ssh-dsa${N0_COLOR}"
			else
				_keytest="${ci_user_pubkey}"
			fi
		else
			# get realpath: lookup current dir and $workdir
			if [ -r "${CIX_PWD}/${ci_user_pubkey}" ]; then
				ci_user_pubkey=$( ${REALPATH_CMD} ${CIX_PWD}/${ci_user_pubkey} )
			elif [ -r "${workdir}/${ci_user_pubkey}" ]; then
				ci_user_pubkey=$( ${REALPATH_CMD} ${workdir}/${ci_user_pubkey} )
			else
				jdestroy jname=${jname} || true
				err 1 "${N1_COLOR}${CIX_APP}: cloudinit: relative keyfile not found: ${N2_COLOR}${ci_user_pubkey} (in $CIX_PWD or $workdir)${N0_COLOR}"
			fi
			_keytest=$( ${GREP_CMD} -v '#' ${ci_user_pubkey} | ${GREP_CMD} . | ${HEAD_CMD} -n1 )
			if ! is_valid_ssh_key "${_keytest}"; then
				jdestroy jname=${jname} || true
				${ECHO} "${N1_COLOR}${CIX_APP}: cloudinit: invalid ssh key from ${ci_user_pubkey} file. valid key: ssh-rsa,ssh-ed25519,ecdsa-*,ssh-dsa${N0_COLOR}"
				err 1 "${N1_COLOR}found: [${N2_COLOR}${_keytest}${N1_COLOR}]${N0_COLOR}"
			fi
		fi
	fi
	[ ! -d ${data}/root/.ssh ] && ${MKDIR_CMD} -m 0700 ${data}/root/.ssh
	echo "${_keytest}" >> ${data}/root/.ssh/authorized_keys
	${CHMOD_CMD} 0644 ${data}/root/.ssh/authorized_keys
fi

# ci_gw4?
if [ "${vnet}" = "1" -a "${ver}" != "empty" ]; then
	_check_ip=0
	case "${ip4_addr}" in
		[Rr][Ee][Aa][Ll][Dd][Hh][Cc][Pp])
			updateconf ${data}/etc/rc.conf ifconfig_eth0="DHCP"
			;;
		[Dd][Hh][Cc][Pp])
			_check_ip=1
			capture ip4_addr dhcpd
			_ret=$?
			case "${_ret}" in
				0)
					true
					;;
				1)
					${ECHO} "${W1_COLOR}${CIX_APP} dhcp error, please check: ${N2_COLOR}cbsd dhcpd${N0_COLOR}"
					;;
				2)
					${ECHO} "${W1_COLOR}${CIX_APP} dhcp error: pools are exhausted (no free IPs in 'nodeippool'?, please check: ${N2_COLOR}cbsd dhcpd${N0_COLOR}"
					;;
			esac
			;;
		[Dd][Hh][Cc][Pp][vV]6)
			_check_ip=1
			capture ip4_addr dhcpdv6
			_ret=$?
			case "${_ret}" in
				0)
					true
					;;
				1)
					${ECHO} "${W1_COLOR}${CIX_APP} dhcp error, please check: ${N2_COLOR}cbsd dhcpd${N0_COLOR}"
					;;
				2)
					${ECHO} "${W1_COLOR}${CIX_APP} dhcp error: pools are exhausted (no free IPs in 'nodeippool'?, please check: ${N2_COLOR}cbsd dhcpd${N0_COLOR}"
					;;
			esac
			;;
		*)
			;;
	esac

	if [ ${_check_ip} -eq 1 ]; then
		iptype ${ip4_addr}
			_ret=$?
			case "${_ret}" in
				0)
					${ECHO} "${W1_COLOR}${CIX_APP} dhcp error, unknown IP type: ${N2_COLOR}cbsd dhcpd${N0_COLOR}"
					;;
				1)
					updateconf ${data}/etc/rc.conf ifconfig_eth0="inet ${ip4_addr} up"
					jset jname=${jname} ip4_addr="${ip4_addr}"
					;;
				2)
					updateconf ${data}/etc/rc.conf ifconfig_eth0="inet6 ${ip4_addr} up"
					jset jname=${jname} ip4_addr="${ip4_addr}"
					;;
			esac
	fi

	if [ -n "${ci_gw4}" ]; then
		if [ "${ci_gw4}" != "0" ]; then
			updateconf ${data}/etc/rc.conf defaultrouter="${ci_gw4}"
		fi
	fi
fi

jswmode jname=${jname} mode=master comment='0'
cbsdsqlro_vars local "SELECT jid FROM jails WHERE jname='${jname}'" myjid

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

# sysrc: post-create sysrc(8) for any jail rc.conf customization
[ -n "${osysrc}" ] && sysrc="${osysrc}"
if [ -n "${sysrc}" ]; then
	/bin/sh <<________EOF
	${CIX_DISTDIR}/misc/cbsdsysrc -qf ${data}/etc/rc.conf ${sysrc} > /dev/null 2>&1
________EOF
fi

cbsdsqlrw ${jailsysdir}/${jname}/local.sqlite "${SQL_JAIL_BULK}"

# pkg bootstrap area
. ${subrdir}/jcreate.subr
jswmode jname=${jname} mode=maintenance comment='Jail Initialization...'

# always mount datadir/fstabs
mountbase -v ${ver} -a ${arch}
mountfstab jname=${jname}

# pkg bootstrap && user accounting
if [ "${ver}" != "empty" ]; then
	postcreate_module_action ${jname} ${jconf}
	ret=$?
	# if ret != 0, remove jail: something wrong
	if [ ${ret} -ne 0 ]; then
		[ ${quiet} -ne 1 ] && ${ECHO}
		[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Creating ${jname} failed: ${N2_COLOR}postcreate_module_action${N0_COLOR}"
		# cleanup
		[ -f "${mount_fstab}" ] && ${RM_CMD} -f ${mount_fstab}
		jremove jname=${jname}
		exit ${ret}
	fi
fi

[ ${quiet} -ne 1 ] && echo 1>&2
[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}To edit VM properties use: ${N2_COLOR}cbsd jconfig jname=${jname}${N0_COLOR}" 1>&2
[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}To start VM use: ${N2_COLOR}cbsd jstart ${jname}${N0_COLOR}" 1>&2
[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}To stop VM use: ${N2_COLOR}cbsd jstop ${jname}${N0_COLOR}" 1>&2
[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}To remove VM use: ${N2_COLOR}cbsd jremove ${jname}${N0_COLOR}" 1>&2
[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}For attach VM console use: ${N2_COLOR}cbsd jlogin ${jname}${N0_COLOR}" 1>&2
[ ${quiet} -ne 1 ] && echo 1>&2
[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Creating ${jname} complete: ${N2_COLOR}Enjoy!${N0_COLOR}" 1>&2
${RM_CMD} -f ${rcconf}
#[ "${mdsize}" != "0" ] && unmountmd jroot=${data}

# always start jail when img_helpers exist
if [ -n "${with_img_helpers}" ]; then
	jswmode jname=${jname} mode=master comment='0'
	jstart jname=${jname} quiet=${quiet} cleanup=0
	get_jid

	for i in ${with_img_helpers}; do
		if [ ! -r "${i}" ]; then
			${ECHO} "${N1_COLOR}Helper doesn't available by path: ${N2_COLOR}${i}${N0_COLOR}"
			continue
		else
			install_and_apply_helpers ${i}
		fi
	done
else
	jswmode jname=${jname} mode=master comment='0'
fi

[ -n "${orunasap}" ] && runasap="${orunasap}"
# autostart asap upon jail created
if [ "${runasap}" = "1" -a ${myjid} -eq 0 ]; then
	jstart jname=${jname} quiet=${quiet} cleanup=0
	cbsdsqlro_vars local "SELECT jid FROM jails WHERE jname='${jname}'" myjid
fi

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

if [ "${etcupdate_init}" = "1" ]; then
	# bootstrap for version
	etcupdate jname=${jname} mode=extract default_obtain_etcupdate_method=index ver=${ver} arch=${arch} target_arch=${target_arch}
fi

if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
	[ -n "${cbsd_jail_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_jail_queue_name} id="${jname}" cmd=jcreate status=2 data_status=${data_status}
fi

# API compat: ~cbsd/jails-system/info*.*
${miscdir}/daemonize ${toolsdir}/save-jail-info jname=${jname}

gettime end_time
diff_time=$(( end_time - st_time ))
if [ "${mod_cbsd_redis_enabled}" = "YES" -a -z "${MOD_CBSD_REDIS_DISABLED}" ]; then
	cbsdredis publish cbsd_events '{"cmd":"jcreate", "node":"'${nodename}'", "jail":"'${jname}'", "status":0, "ip4_addr":"'${ip4_addr}'","duration":'${diff_time}'}'
fi

capture diff_time displaytime ${diff_time}

[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}${CIX_APP} done ${N2_COLOR}in ${diff_time}${N0_COLOR}"
cbsdlogger NOTICE ${CIX_APP}: jail ${jname} has been created in ${diff_time}

# hook
hooks_exist=0
if cix_read_dir ${jailsysdir}/${jname}/master_create.d/ >/dev/null 2>&1; then
	hooks_exists=1
fi

if cix_read_dir ${jailsysdir}/${jname}/create.d/ >/dev/null 2>&1; then
	hooks_exists=1
fi

if [ ${hooks_exist} -eq 1 ]; then
	geniplist	${ip4_addr}			# for ipvX_first_public-like vars
	export_jail_data_for_external_hook
	external_exec_master_script "master_create.d"
	external_exec_script -s create.d -a
fi

[ -n "${oremovejconf}" ] && removejconf="${oremovejconf}"
if [ ${removejconf} = "1" ]; then
	${RM_CMD} -f ${jconf} > /dev/null 2>&1
fi

exit 0
