#!/usr/local/bin/cbsd
#v12.0.12
MYARG="dstdir jname media"
MYOPTARG="applytpl dstname efi freesize fromfile gw4 host_hostname inter ip4_addr label name nameserver nic nobase product prunelist publisher quiet swapsize timezone ver vm_guestfs"
MYDESC="Convert jail into cd9660 ISO or memstick image"
ADDHELP="

${H3_COLOR}Description${N0_COLOR}:

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}applytpl=${N0_COLOR}     = manage rc.conf for image, e.g set ip,hostname,nameserver. default - 1, apply
 ${N2_COLOR}dstdir=${N0_COLOR}       = destination dir for storing jname.iso
 ${N2_COLOR}dstname=${N0_COLOR}      = for alternative image name
 ${N2_COLOR}efi=${N0_COLOR}          = - set 0 to disable efi by default (if efiboot.img exist its preffered boot method)
 ${N2_COLOR}freesize=${N0_COLOR}     = reserved (expand to) X size of image free space (100m, 1g)
 ${N2_COLOR}fromfile=${N0_COLOR}     = - Read arguments from file
 ${N2_COLOR}gw4=${N0_COLOR}          = gateway for IPv4
 ${N2_COLOR}host_hostname=${N0_COLOR}  set hostname in rc.conf image (freebsd only)
 ${N2_COLOR}ip4_addr=${N0_COLOR}     = set ip4 addr or 'DHCP' in rc.conf image (freebsd only
 ${N2_COLOR}jname=${N0_COLOR}        = source data jail name
 ${N2_COLOR}label=${N0_COLOR}        = label for media
 ${N2_COLOR}media=${N0_COLOR}        = iso,memstick,livecd or bhyve
 ${N2_COLOR}name=${N0_COLOR}         = for alternative kernel name (GENERIC is default)
 ${N2_COLOR}nameserver=${N0_COLOR}   = set nameserver in image (freebsd only)
 ${N2_COLOR}nic=${N0_COLOR}          = specify network nic for ip4_addr
 ${N2_COLOR}prunelist=${N0_COLOR}    = path to prunelist, default is \${sharedir}/jail2iso-prunelist. 0 for disable.
 ${N2_COLOR}swapsize=${N0_COLOR}     = - Allocate/configure SWAP partition to X size
 ${N2_COLOR}timezone=${N0_COLOR}     = set timezone in image (freebsd only)
 ${N2_COLOR}vm_guestfs=${N0_COLOR}   = ufs or zfs. Default is: ufs

${H3_COLOR}Examples${N0_COLOR}:

"
EXTHELP="wf_jail2iso"

. ${subrdir}/nc.subr

readconf buildworld.conf
readconf jail2iso.conf

# todo: to conf
EFI_PART_SIZE="260m"			# default FreeBSD efi partition

applytpl=1
ver=
over=
. ${cbsdinit}

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

oapplytpl="${applytpl}"

. ${system}
. ${subrdir}/zfs.subr
. ${subrdir}/universe.subr
. ${subrdir}/bhyve.subr
. ${subrdir}/build.subr

# todo: get rid of bsdlabel deps
# bsdlabel not available on != i386/amd64 arch, see:
# /usr/src/sbin/bsdlabel/Makefile
# https://forums.freebsd.org/threads/no-bsdlabel-command-in-aarch64.77721/
[ -z "${BSDLABEL_CMD}" -o ! -x "${BSDLABEL_CMD}" ] && err 1 "${N1_COLOR}${CBSD_APP}: no such bsdlabel command${N0_COLOR}"

. ${subrdir}/rcconf.subr
[ $? -eq 1 ] && err 1 "${N1_COLOR}no such jail: ${N2_COLOR}${jname}${N0_COLOR}"

# restore orig ver after rcconf
[ -n "${over}" ] && ver="${over}"

[ ${jid} -ne 0 ] && err 1 "${N1_COLOR}jail is active. please stop them first: ${N2_COLOR}${jname}${N0_COLOR}"

[ -r "${fromfile}" ] && . ${fromfile}
[ -z "${quiet}" ] && quiet=0
[ -z "${efi}" ] && efi=1
[ -z "${swapsize}" ] && swapsize=0
[ -z "${vm_guestfs}" ] && vm_guestfs="ufs"

[ "${media}" = "bhyve" -a -z "${freesize}" ] && err 1 "${N1_COLOR}For media=bhyve please set freesize= value. For example: ${N2_COLOR}freesize=1g${N0_COLOR}"

init_target_arch
init_srcdir
init_supported_arch
init_basedir
init_kerneldir

[ -n "${label}" ] && LABEL="${label}"
[ -n "${product}" ] && PRODUCT="${product}"
[ -n "${publisher}" ] && PUBLISHER="${publisher}"

TMP_DIR="${tmpdir}/${jname}-iso.$$"
DST_DIR="${tmpdir}${tmpdir}mfsroot.$$"

TRAP=

clear_tmp_dir()
{
	if [ -d "${TMP_DIR}" -o -f "${TMP_DIR}" ]; then
		nice -n 19 ${IDPRIO_CMD} 29 ${CHFLAGS_CMD} -R noschg ${TMP_DIR}
		${RM_CMD} -rf ${TMP_DIR}
	fi
}

# Prepare MFSRoot part
prepare_dir()
{
	local rcscript="/etc/rc.d/preparedir"

	${CP_CMD} -rP ${path}/etc ${DST_DIR}/

	case "${media}" in
		iso)
			MOUNTROOT="${MOUNT_CMD} -oro -t cd9660 /dev/iso9660/${LABEL} /mnt"
			;;
		memstick)
			MOUNTROOT="${MOUNT_CMD} -oro /dev/ufs/${LABEL} /mnt"
			;;
	esac

	${CAT_CMD} > ${DST_DIR}${rcscript} <<EOF
#!/bin/sh
#
# Copyright (c) 2015-2020 CBSD Team

# PROVIDE: preparedir
# KEYWORD: nojail
# BEFORE: sysctl

export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin

MOUNTOK=0
maxretry=10
retry=0

if [ ! -d /mnt/bin ]; then
	printf "Waiting \${maxretry}s for mount root"
	while [ \$MOUNTOK -ne 1 ]; do
		printf "."
		${MOUNTROOT} > /dev/null 2>&1
		if [ \$? -ne 0 ]; then
			sleep 1
			retry=\$((retry+1))
		else
			echo
			MOUNTOK=1
		fi
		if [ \$retry -ge \${maxretry} ]; then
			echo
			echo "Unsuccess. Drop to single mode"
			echo "Mount command: ${MOUNTROOT}"
			exit 0
		fi
	done
fi

if [ ! -d /usr/bin ]; then
	MD=\$( ${MDCONFIG_CMD} -o readonly -a -t vnode -f /mnt/usr.uzip )
	${MOUNT_CMD} -oro /dev/\${MD}.uzip /mnt/usr
	${MOUNT_CMD} -oro -t nullfs /mnt/usr /usr
	${MOUNT_CMD} -oro -t nullfs /mnt/boot /boot
	hash -r
fi
EOF

	${CHMOD_CMD} 0555 ${DST_DIR}${rcscript}

	[ -f "${path}/etc/rc.conf" ] && ${CP_CMD} ${path}/etc/rc.conf ${DST_DIR}/etc/rc.conf

	# Here is mfsroot location
	if [ -f "${jailsysdir}/${jname}/tmpfsdir" ]; then
		${CP_CMD} ${miscdir}/tmpfsdir ${DST_DIR}/etc/rc.d/
	fi
}

prunelist()
{
	[ ! -f "${prunelist}" ] && return 0 # no prune
	[ -z "${1}" ] && return 0 # sanity

	${ECHO} "${N1_COLOR}Prune file by list: ${N2_COLOR}${prunelist}${N0_COLOR}"

	for FILE in $( ${CAT_CMD} ${prunelist} ); do
		[ -z "${FILE}" ] && continue
		case ":${FILE}" in
			:#* | :)
				continue
				;;
		esac
		${RM_CMD} -rf ${1}/${FILE} 2>/dev/null
	done
}

# $1 - rootdir
epilogue_img()
{
	local _rootfs="${1}"
	[ -z "${_rootfs}" -a ! -d "${_rootfs}" ] && return 0
	[ -z "${nic}" ] && nic="DEFAULT"

	${ECHO} "${N1_COLOR}Epilogue for ${N2_COLOR}${_rootfs}${N0_COLOR}"

	# for ISO too?
	[ "${media}" = "memstick" ] && return 0

	${SYSRC_CMD} -qf ${_rootfs}/etc/rc.conf fsck_y_enable="YES" >/dev/null

	[ -n "${host_hostname}" ] && ${SYSRC_CMD} -qf ${_rootfs}/etc/rc.conf hostname="${host_hostname}" >/dev/null

	if [ -n "${ip4_addr}" -a "${ip4_addr}" != "0" ]; then
		case "${ip4_addr}" in
			[Dd][Hh][Cc][Pp])
				${SYSRC_CMD} -qf ${_rootfs}/etc/rc.conf ifconfig_${nic}="DHCP" >/dev/null
				;;
			*)
				${SYSRC_CMD} -qf ${_rootfs}/etc/rc.conf ifconfig_${nic}="inet ${ip4_addr}" >/dev/null
		esac
	fi

	[ -n "${gw4}" ] && ${SYSRC_CMD} -qf ${_rootfs}/etc/rc.conf defaultrouter="${gw4}" >/dev/null

	if [ -n "${nameserver}" ]; then
		IFS=","
		for i in ${nameserver}; do
			echo "nameserver ${i}" >> ${_rootfs}/etc/resolv.conf
		done
		IFS=" "
	fi

	if [ -n "${timezone}" ]; then
		[ -f "/usr/share/zoneinfo/${timezone}" ] && ${CP_CMD} /usr/share/zoneinfo/${timezone} ${_rootfs}/etc/localtime
	fi
}


makemfsroot()
{
	local _filelist _ver
	local _tmpdir=$( ${MKTEMP_CMD} -d )

	mfsrootfile="${tmpdir}/mfsroot.$$"

	_ver=${ver%%.*}

	_filelist="${distsharedir}/${platform}-filemin_${_ver}.txt.xz"

	[ ! -r ${_filelist} ] && err 1 "${N1_COLOR}${CBSD_APP}: no such index file: ${N2_COLOR}${_filelist}${N0_COLOR}"

	${ECHO} "${N1_COLOR}mfsroot index: ${N2_COLOR}${_filelist}${N0_COLOR}"

	copy-binlib filelist=${_filelist} dstdir=${_tmpdir} basedir=${BASE_DIR} chaselibs=1 mtree=1

	preparebase dst=${_tmpdir}

	local _size=0

#	_size=$(${FIND_CMD} ${_tmpdir} | while read _myfile; do
#		_size=$((_size + `/usr/bin/stat -f %z ${_myfile}`))
#		echo ${_size}
#	done |${TAIL_CMD} -n1 )

#	_size=$(( _size / 1024 / 1024 ))
#	_size=$(( _size + 10 ))
#	_size=$(( _size * 1024 ))

#	echo "$_size"

	# NOT REL
	_size=80000
#	_size=230000

	${DD_CMD} if=/dev/zero of=${mfsrootfile} count=${_size} bs=1k
	DEV=$( ${MDCONFIG_CMD} -a -t vnode -f ${mfsrootfile} )
	${BSDLABEL_CMD} -w /dev/${DEV} auto
	nice -n 19 ${IDPRIO_CMD} 29 ${NEWFS_CMD} -n -i ${BS} -m 0 -o space /dev/${DEV}
	${MKDIR_CMD} -p ${DST_DIR}
	${MOUNT_CMD} /dev/${DEV} ${DST_DIR}
	cd ${_tmpdir} && nice -n 19 ${IDPRIO_CMD} 29 ${FIND_CMD} -E ${_tmpdir} \( -type f -or -type d -or -type l \) -print | ${SED_CMD} s:${_tmpdir}:./:g | nice -n 19 ${IDPRIO_CMD} 29 ${CPIO_CMD} -pdmu ${DST_DIR}

	nice -n 19 ${IDPRIO_CMD} 29 ${CHFLAGS_CMD}  -R noschg ${_tmpdir}
	${RM_CMD} -rf ${_tmpdir}
	prepare_dir
	[ "${prunelist}" != "0" ] && prunelist ${DST_DIR}
	cd /
	# make flags for preparedir script
	[ -d "${DST_DIR}/usr/bin" ] && ${RM_CMD} -rf ${DST_DIR}/usr/bin
	${UMOUNT_CMD} -f ${DST_DIR} && ${RMDIR_CMD} ${DST_DIR}
	${MDCONFIG_CMD} -d -u ${DEV}

	${ECHO} "${N1_COLOR}${CBSD_APP} mfsroot done, temp md: ${N2_COLOR}${DEV}${N0_COLOR}" 1>&2
}


show_bhyve_message()
{
	if [ ${freebsdhostversion} -lt 1300021 ]; then
		local _tap_module="if_tap"
	else
		local _tap_module="if_tuntap"
	fi

	$ECHO "${N1_COLOR}Completed. Image ready for bhyve, example:${N0_COLOR}"
	${CAT_CMD} << EOF
 % kldload vmm
 % kldload ${_tap_module}
 % sysctl -w net.link.tap.up_on_open=1
 % ifconfig tap0 create
 % ifconfig bridge0 create
EOF
    ${ECHO} " % ifconfig bridge0 addm ${mynic} addm tap0    ${N2_COLOR}<< -- where ${mynic} is uplink${N0_COLOR}"
    ${CAT_CMD} << EOF
 % ifconfig bridge0 up
 % sh /usr/share/examples/bhyve/vmrun.sh -d ${dstdir}/${dstname} ${jname}
EOF
}

# $1 - source dir
# $2 - dst file image
create_img_for_dir()
{
	local base_size minfree1 minfree2
	local _res _msg
	local _reserved_size="512m"		# free reserved size
	local _efi_size="${EFI_PART_SIZE}"

	if is_number "${_reserved_size}"; then
		if conv2bytes ${_reserved_size}; then
			_reserved_size="${convval}"
		fi
	fi

	if is_number "${_efi_size}"; then
		if conv2bytes ${_efi_size}; then
			_efi_size="${convval}"
		fi
	fi

	[ -z "${freesize}" ] && freesize=0
	[ -z "${imgfreesize}" ] && imgfreesize=0

	if [ -d "${1}" ]; then
		base_size=$( ${DU_CMD} -sk ${1} | ${AWK_CMD} '{printf $1"k"}' )
	else
		base_size=0
	fi

	if is_number ${freesize}; then
		if conv2bytes ${freesize}; then
			freesize="${convval}"
		fi
	fi

	if is_number ${swapsize}; then
		if conv2bytes ${swapsize}; then
			swapsize="${convval}"
		fi
	fi

	if is_number ${imgfreesize}; then
		if conv2bytes ${imgfreesize}; then
			imgfreesize="${convval}"
		fi
	fi

	if is_number ${base_size}; then
		if conv2bytes ${base_size}; then
			base_size="${convval}"
		fi
	fi

	# we need calculate 8% minfree from base_size
	# minfree=$(( base_size * 8 / 100 ))
	minfree1=$(( base_size * 9 / 100 )) # 9% - du -sk and conv2bytes fault compensation
	minfree2=$(( freesize * 9 / 100 )) # 9% - du -sk and conv2bytes fault compensation

	all_size=$(( base_size + freesize + minfree1 + minfree2 + imgfreesize + swapsize + _reserved_size + _efi_size ))
	#fs_size=$(( base_size + freesize + minfree1 + minfree2 ))
	# ?? recalc
	fs_size="${freesize}"

	if conv2human "${all_size}"; then
		all_size=${convval}
	fi

	echo "r: ${_reserved_size} , e: ${_efi_size} "
	echo "virtual_create_dsk -p ${2} -s ${all_size} -f 0 -t md"

	# todo: type zvol
	_msg=$( virtual_create_dsk -p ${2} -s ${all_size} -f 0  -t md )
	_res=$?
	if [ ${_res} -ne 0 ]; then
		err 1 "Error: Couldn't create the image file. ${_msg}"
	fi
}


bhyve_zfs_install()
{
	local mnttmp tmpjname
	local _ret
	${KLDSTAT_CMD} -qm zfs || ${KLDLOAD_CMD} zfs
	mnttmp=$( ${MKTEMP_CMD} -d )

	local poolname="tank"
	local freepool=0
	local poolnum=0
	local mypool="${poolname}" # first version of poolname, without index

	mypool=$( while [ ${freepool} -eq 0 ]; do
		${ZPOOL_CMD} get -Ho value guid ${mypool} > /dev/null 2>&1
		[ $? -eq 1 ] && freepool=1 && echo "${mypool}" && exit 0  # No such pool here, so take it
		[ ${poolnum} -gt 10 ] && err 1 "${mypool}"
		poolnum=$(( poolnum + 1 ))
		mypool="${poolname}${poolnum}"
	done )

	[ $? -ne 0 ] && err 1 "${N1_COLOR}Can't find free pool name: ${N2_COLOR}${mypool}${N0_COLOR}"

	if [ "${baserw}" = "0" ]; then
		mountbase -o "" -p "" -d "" -c "" -s ""
		if  [ "${ver}" != "empty" ]; then
				[ -f "${mount_fstab}" ] && mountfstab jroot=${path} fstab=${mount_fstab} jname="${jname}" > /dev/null 2>&1
				[ -f "${mount_fstab}.local" ] && mountfstab jroot=${path} fstab=${mount_fstab}.local jname="${jname}" > /dev/null 2>&1
		fi
	fi

	if [ ${baserw} -eq 1 ]; then
		srcdata=${data}
	else
		srcdata=${path}
	fi
	echo "zfsinstall devs=${unit} ver=${ver} arch=${arch} srcdata=${srcdata} mnt=${mnttmp} pool=${mypool} swap=\"${swapsize}\" quiet=1"
	zfsinstall devs=${unit} ver=${ver} arch=${arch} srcdata=${srcdata} mnt=${mnttmp} pool=${mypool} swap="${swapsize}" quiet=1
	_ret=$?
	echo "RET ${_ret}"
	[ ${_ret} -ne 0 ] && err 1 "${N1_COLOR}jail2iso: zfsinstall error${N0_COLOR}"

	# hack for remove all dirty zpool 
	${CAT_CMD} > ${mnttmp}/etc/rc.local <<EOF
${ZPOOL_CMD} list | ${GREP_CMD} UNAVAIL |${AWK_CMD} '{printf \$1"\n"}' |while read _zpool; do
${ZPOOL_CMD} destroy \${_zpool} >/dev/null 2>&1
done

# detect for swap
FSWAP=\$( ${GPART_CMD} list | ${GREP_CMD} -B50 "type: freebsd-swap" | ${GREP_CMD} Name: | ${TAIL_CMD} -n1 |${AWK_CMD} '/Name:/{print \$3}' )

if [ -n "\$FSWAP" ]; then
	echo "/dev/\${FSWAP} none swap sw 0 0" > /etc/fstab
	/sbin/swapon -a
fi

${RM_CMD} -f /etc/rc.local
EOF
	[ ${oapplytpl} -eq 1 ] && epilogue_img ${mnttmp}

	post_module_action ${mnttmp}

	${UMOUNT_CMD} ${mnttmp}/var > /dev/null 2>&1
	${UMOUNT_CMD} ${mnttmp}/tmp > /dev/null 2>&1
	${UMOUNT_CMD} ${mnttmp} > /dev/null 2>&1
	${RMDIR_CMD} ${mnttmp} > /dev/null 2>&1
	${ZPOOL_CMD} export -f ${mypool}
}

check_for_external_mount()
{
	local _i _checkpath="${path}/usr/ports/distfiles ${path}/usr/ports/packages ${path}/usr/src ${path}/usr/obj ${path}/usr/ports ${path}/usr/src"

	for _i in ${_checkpath}; do
		if is_mounted ${_i}; then
			if getyesno "${N1_COLOR}external mount: ${N2_COLOR}${_i}${N1_COLOR}, unmount first?${N0_COLOR}"; then
				${UMOUNT_CMD} -f ${_i}
			fi
		fi
	done
}

# Create full FS/data hier in ${TMP_DIR} directory
make_ufs()
{
	${ECHO} "${N1_COLOR}kernel required ver: ${ver}${N0_COLOR}" 1>&2
	# move to kernel init?
	get_kernel

	[ ! -d "${KERNEL_DIR}" ] && err 1 "No such ${KERNEL_DIR}"
	case "${media}" in
		iso|memstick|bhyve|livecd)
			;;
		*)
			err 1 "${N1_COLOR}unknown media type. must be: ${N2_COLOR}iso${N1_COLOR},${N2_COLOR}memstick${N1_COLOR},${N2_COLOR}livecd ${N1_COLOR}or${N2_COLOR} bhyve${N0_COLOR}"
			;;
	esac

	mountbase -o "" -p "" -d "" -c "" -s ""

	if  [ "${ver}" != "empty" ]; then
		if [ "${baserw}" = "0" ]; then
			[ -r "${mount_fstab}" ] && mountfstab jroot=${path} fstab=${mount_fstab} jname="${jname}" > /dev/null 2>&1
			[ -r "${mount_fstab}.local" ] && mountfstab jroot=${path} fstab=${mount_fstab}.local jname="${jname}" > /dev/null 2>&1
		fi
	fi

	check_for_external_mount

	BS=8192
	case "${media}" in
		bhyve|livecd)
			;;
		*)
			makemfsroot
			;;
	esac

	TRAP="${TRAP} clear_tmp_dir;"
	trap "${TRAP}" HUP INT ABRT BUS TERM EXIT
	${MKDIR_CMD} -p ${TMP_DIR}
	#echo "[debug] cd ${path} && nice -n 19 ${IDPRIO_CMD} 29 ${PAX_CMD} -p eme -rw . ${TMP_DIR}"

	echo "make_ufs: media: ${media}"

	# not for iso too ?
	# new comment: why skip here ;-)
#	if [ "${media}" != "memstick" ]; then
#		echo
		echo "[debug]cd ${path} && nice -n 19 ${IDPRIO_CMD} 29 ${PAX_CMD} -p eme -rw . ${TMP_DIR}" 1>&2
		cd ${path} && nice -n 19 ${IDPRIO_CMD} 29 ${PAX_CMD} -p eme -rw . ${TMP_DIR}
		sync
#		echo
#	fi

	[ "${media}" != "bhyve" ] && ${RM_CMD} -rf ${TMP_DIR}/rescue
	[ "${prunelist}" != "0" ] && prunelist ${TMP_DIR}

	# remove archive
	# BAD FOR packages
	#[ "${media}" != "bhyve" ] && ${FIND_CMD} ${TMP_DIR} -type f -name \*.a -delete

	[ ! -d ${TMP_DIR}/boot/kernel ] && ${MKDIR_CMD} -p ${TMP_DIR}/boot/kernel

	${CP_CMD} -a ${KERNEL_DIR}/boot/kernel/* ${TMP_DIR}/boot/kernel/

	if [ ! -r "${TMP_DIR}/boot/kernel/kernel" ]; then
		echo "no such ${TMP_DIR}/boot/kernel/kernel"
		echo "check: ${CP_CMD} -a ${KERNEL_DIR}/boot/kernel/* ${TMP_DIR}/boot/kernel/"
		read p
	fi

	if [ "${media}" != "bhyve" ]; then
		${RM_CMD} -f ${TMP_DIR}/boot/kernel/*.symbols
		cd ${TMP_DIR}/boot/kernel && ${GZIP_CMD} -9 ./kernel
	fi

	if [ -r "${jailsysdir}/${jname}/loader.conf" ]; then
		${ECHO} "${N1_COLOR}${CBSD_APP}: custom loader.conf found${N0_COLOR}"
		${CP_CMD} ${jailsysdir}/${jname}/loader.conf ${TMP_DIR}/boot/loader.conf
	else
		${ECHO} "${N1_COLOR}${CBSD_APP}: custom loader.conf absent in ${jailsysdir}/${jname}/loader.conf${N0_COLOR}"
	fi

	case "${media}" in
		bhyve)
			ROOTFS="/dev/ufs/${LABEL} / ufs rw,noatime 1 1"
			${CAT_CMD} >> ${TMP_DIR}/boot/loader.conf <<EOF
# jail2iso
console="userboot"
hw.efi.poweroff=0
EOF
			${CAT_CMD} > ${TMP_DIR}/etc/fstab <<EOF
${ROOTFS}
EOF
			;;
		livecd)
			ROOTFS="/dev/iso9660/${LABEL} /mnt cd9660 ro 0 0"
${CAT_CMD} >> ${TMP_DIR}/boot/loader.conf <<EOF
# jail2iso
console="userboot"
vfs.root.mountfrom="cd9660:/dev/iso9660/${LABEL}"
hw.efi.poweroff=0
EOF
# $ROOTFS in /etc/fstab not mandatory, already mounted? 
# unionfs for /etc/?
			${CAT_CMD} > ${TMP_DIR}/etc/fstab << EOF
tmpfs /tmp tmpfs rw 0 0
tmpfs /var/run tmpfs rw 0 0
tmpfs /boot/zfs tmpfs rw 0 0
EOF
			;;
		iso)
			ROOTFS="/dev/iso9660/${LABEL} /mnt cd9660 ro 0 0"
			${CAT_CMD} >> ${TMP_DIR}/boot/loader.conf << EOF
hw.efi.poweroff=0
#hw.vga.textmode=1
geom_uzip_load="YES"
tmpfs_load="YES"
nullfs_load="YES"

mfs_load="YES"
mfs_type="mfs_root"
mfs_name="/mfsroot"
vfs.root.mountfrom="ufs:/dev/md0"

net.inet.ip.fw.default_to_accept=1
EOF
			${CAT_CMD} > ${TMP_DIR}/etc/fstab << EOF
tmpfs /tmp tmpfs rw 0 0
${ROOTFS}
/mnt/boot /boot ${NULLFS} ro 0 0
tmpfs /boot/zfs tmpfs rw 0 0
EOF
			;;
		memstick)
			ROOTFS="/dev/ufs/${LABEL} /mnt ufs ro,noatime 1 1"
			${CAT_CMD} >> ${TMP_DIR}/boot/loader.conf << EOF
hw.efi.poweroff=0
#hw.vga.textmode=1
geom_uzip_load="YES"
tmpfs_load="YES"
nullfs_load="YES"

mfs_load="YES"
mfs_type="mfs_root"
mfs_name="/mfsroot"
vfs.root.mountfrom="ufs:/dev/md0"

net.inet.ip.fw.default_to_accept=1
EOF
			${CAT_CMD} > ${TMP_DIR}/etc/fstab << EOF
tmpfs /tmp tmpfs rw 0 0
${ROOTFS}
/mnt/boot /boot ${NULLFS} ro 0 0
tmpfs /boot/zfs tmpfs rw 0 0
EOF
			;;
	esac


	if [ "${swapsize}" != "0" ]; then
		${CAT_CMD} >> ${TMP_DIR}/etc/fstab <<EOF
/dev/gpt/swap	none	swap	sw	0	0
EOF
	fi

	[ ${oapplytpl} -eq 1 ] && echo "Welcome to ${PRODUCT}" > ${TMP_DIR}/etc/motd

	case "${media}" in
		bhyve|livecd)
			${CAT_CMD} > ${TMP_DIR}/etc/ttys <<EOF
console "/usr/libexec/getty std.9600"   vt100   on secure
EOF
			;;
		*)
			${MV_CMD} ${mfsrootfile} ${TMP_DIR}/mfsroot
			cd ${TMP_DIR}
			nice -n 19 ${IDPRIO_CMD} 29 ${GZIP_CMD} -9 ${TMP_DIR}/mfsroot
			TRAP="${TRAP} ${RM_CMD} -f ${tmpdir}/usr.img.$$ ;"
			trap "${TRAP}" HUP INT ABRT BUS TERM EXIT
			nice -n 19 ${IDPRIO_CMD} 29 ${MAKEFS_CMD} -o optimization=space -t ffs ${tmpdir}/usr.img.$$ ${TMP_DIR}/usr
			nice -n 19 ${IDPRIO_CMD} 29 ${MKUZIP_CMD} -o ${TMP_DIR}/usr.uzip ${tmpdir}/usr.img.$$
			${CHFLAGS_CMD} -R noschg ${TMP_DIR}/usr && ${RM_CMD} -rf ${TMP_DIR}/usr && ${MKDIR_CMD} ${TMP_DIR}/usr
			# LiveCD location
			[ -f "${jailsysdir}/${jname}/tmpfsdir" ] && ${CP_CMD} ${jailsysdir}/${jname}/tmpfsdir ${TMP_DIR}/etc/
			;;
	esac

	# post action inside image
	[ ${oapplytpl} -eq 1 ] && epilogue_img ${TMP_DIR}
}


# rootpath
post_module_action()
{
	local TMPFILE
	local rootpath
	local tmpjname

	[ -n "${1}" ] && rootpath="${1}"

	[ ! -d "${rootpath}" ] && return 0

	tmpjname=$( path2jail root=${rootpath} )

	# create temporary jail for post-action
	. ${subrdir}/jcreate.subr
	TMPFILE=$( ${MKTEMP_CMD} )

	if [ -r "${fromfile}" ]; then
		${CP_CMD} -a ${fromfile} ${TMPFILE}
		${SYSRC_CMD} -qf ${TMPFILE} -x jname
		${SYSRC_CMD} -qf ${TMPFILE} path="${rootpath}"
		${SYSRC_CMD} -qf ${TMPFILE} data="${rootpath}"
	else

		# additional area
		[ -n "${user_pw_root}" ] && ${CAT_CMD} >> ${TMPFILE} <<EOF
user_pw_root='${user_pw_root}';
EOF

		[ -n "${pkglist}" ] && echo "pkglist=\"${pkglist}\";" >> ${TMPFILE}
		if [ -n "${srvlist}" -a -r "${srvlist}" ]; then
			${CAT_CMD} ${srvlist} >> ${TMPFILE}
			${RM_CMD} -f ${srvlist}
		fi
	fi

	# end of additional area
	# pkg bootstrap && user accounting
	postcreate_module_action ${tmpjname} ${TMPFILE}

	${RM_CMD} -f ${TMPFILE}
	jcleanup jname=${tmpjname}

	JAILRCCONF="${jailrcconfdir}/rc.conf_${tmpjname}"
	# make sure jail is offline 
	jstop jname=${tmpjname} > /dev/null 2>&1
	junregister jname=${tmpjname}
	[ -f "${JAILRCCONF}" ] && ${RM_CMD} -f ${JAILRCCONF}
}

# MAIN

jcleanup jname=${jname}
clear_tmp_dir
[ ${baserw} -eq 1 ] && path=${data}

[ "${prunelist}" != "0" ] && prunelist="${sharedir}/jail2iso-prunelist"
if [ "${nobase}" != "1" ]; then
	[ ! -d "${BASE_DIR}" ] && err 1 "${N1_COLOR}No base data on: ${N2_COLOR}${BASE_DIR}${N0_COLOR}"
fi

[ -z "${dstname}" ] && dstname="${jname}-${ver}_${arch}.img"

case "${media}" in
	iso)
		make_ufs
		echo "make_ufs done"
		[ -z "${dstname}" ] && dstname="${jname}-${ver}_${arch}.iso"
		echo "/usr/local/cbsd/release/mkisoimages.sh -l ${LABEL} -n ${dstdir}/${dstname} -d ${TMP_DIR} -e ${efi}"
		/usr/local/cbsd/release/mkisoimages.sh -l ${LABEL} -n ${dstdir}/${dstname} -d ${TMP_DIR} -e ${efi}
		;;
	memstick)
		make_ufs

		${MAKEFS_CMD} -B little -o version=2 -o softupdates=1 -o label=${LABEL} ${dstdir}/${dstname}.part ${TMP_DIR}
		[ $? -ne 0 ] && err 1 "makefs failed"

		if [ ${efi} -eq 1 ]; then
			# efifat was deprecated in 12.2-RELEASE
			if [ -r ${TMP_DIR}/boot/boot1.efifat ]; then
				${MKIMG_CMD} -s gpt -b ${TMP_DIR}/boot/pmbr -p efi:=${TMP_DIR}/boot/boot1.efifat -p freebsd-boot:=${TMP_DIR}/boot/gptboot -p freebsd-ufs:=${dstdir}/${dstname}.part -p freebsd-swap::1M -o ${dstdir}/${dstname}
			elif [ -r ${TMP_DIR}/boot/boot1.efi ]; then
				_efi_part=$( ${MKTEMP_CMD} )
				${TRUNCATE_CMD} -s64M ${_efi_part}
				unit=$( ${MDCONFIG_CMD} -a -t vnode -f ${_efi_part} 2>&1 )
				[ $? -ne 0 ] && err 1 "${N1_COLOR}${CBSD_APP}: mdconfig ${W1_COLOR}failed${N2_COLOR} ${unit}${N0_COLOR}"
				echo "stamp loader.efi: ${_efi_part}"
				tmp_mp=$( ${MKTEMP_CMD} -d )
				/sbin/newfs_msdos -F 32 -c 1 -L EFISYS /dev/${unit}
				${MOUNT_CMD} -t msdosfs /dev/${unit} ${tmp_mp}
				${MKDIR_CMD} -p ${tmp_mp}/EFI/BOOT
				${CP_CMD} /boot/loader.efi ${tmp_mp}/EFI/BOOT/BOOTX64.efi
				${UMOUNT_CMD} ${tmp_mp}
				${RMDIR_CMD} ${tmp_mp}
				${MDCONFIG_CMD} -d -u ${unit}
				${MKIMG_CMD} -s gpt -b ${TMP_DIR}/boot/pmbr -p efi:=${_efi_part} -p freebsd-boot:=${TMP_DIR}/boot/gptboot -p freebsd-ufs:=${dstdir}/${dstname}.part -p freebsd-swap::1M -o ${dstdir}/${dstname}
			else
				err 1 "${N1_COLOR}${CBSD_APP}: no such boot1.efi or loader.efi${N0_COLOR}"
			fi
		else
			${MKIMG_CMD} -s gpt -b ${TMP_DIR}/boot/pmbr -p freebsd-boot:=${TMP_DIR}/boot/gptboot -p freebsd-ufs:=${dstdir}/${dstname}.part -p freebsd-swap::1M -o ${dstdir}/${dstname}
		fi
		${RM_CMD} -f ${dstdir}/${dstname}.part

		${ECHO} "${N1_COLOR}Now you can burn image to USB memstick via\n ${N2_COLOR}dd if=${dstdir}/${dstname} of=/dev/da${W2_COLOR}X${N2_COLOR} bs=1m conv=\"sync\"${N0_COLOR}"
		;;
	bhyve|livecd)
		case "${vm_guestfs}" in
			ufs)
				make_ufs
				echo "${MAKEFS_CMD} -B little -o version=2 -o softupdates -o label=${LABEL} ${dstdir}/${dstname}.part ${TMP_DIR}"
				${MAKEFS_CMD} -B little -o version=2 -o softupdates=1 -o label=${LABEL} ${dstdir}/${dstname}.part ${TMP_DIR}
				[ $? -ne 0 ] && err 1 "makefs failed"
				echo "makefs done: ${dstdir}/${dstname}.part"
				if [ -n "${swapsize}" -a "${swapsize}" != "0" ]; then
					_swap_args="-p freebsd-swap::${swapsize}"
				else
					_swap_args=
				fi

				if [ "${media}" = "livecd" ]; then
					echo "/usr/local/cbsd/release/mkisoimages.sh -l ${LABEL} -n ${dstdir}/${dstname} -d ${TMP_DIR} -e ${efi}"
					/usr/local/cbsd/release/mkisoimages.sh -l ${LABEL} -n ${dstdir}/${dstname} -d ${TMP_DIR} -e ${efi}
					exit 0
				fi
				if [ ${efi} -eq 1 ]; then
					# efifat was deprecated in 12.2-RELEASE
					if [ -r ${TMP_DIR}/boot/boot1.efifat ]; then
						${MKIMG_CMD} -s gpt -b ${TMP_DIR}/boot/pmbr -p efi:=${TMP_DIR}/boot/boot1.efifat -p freebsd-boot:=${TMP_DIR}/boot/gptboot ${_swap_args} -p freebsd-ufs:=${dstdir}/${dstname}.part -o ${dstdir}/${dstname}
					elif [ -r ${TMP_DIR}/boot/boot1.efi ]; then
						_efi_part=$( ${MKTEMP_CMD} )
						${TRUNCATE_CMD} -s64M ${_efi_part}
						unit=$( ${MDCONFIG_CMD} -a -t vnode -f ${_efi_part} 2>&1 )
						[ $? -ne 0 ] && err 1 "${N1_COLOR}${CBSD_APP}: mdconfig ${W1_COLOR}failed${N2_COLOR} ${unit}${N0_COLOR}"
						echo "stamp loader.efi: ${_efi_part}"
						tmp_mp=$( ${MKTEMP_CMD} -d )
						/sbin/newfs_msdos -F 32 -c 1 -L EFISYS /dev/${unit}
						${MOUNT_CMD} -t msdosfs /dev/${unit} ${tmp_mp}
						${MKDIR_CMD} -p ${tmp_mp}/EFI/BOOT
						${CP_CMD} /boot/loader.efi ${tmp_mp}/EFI/BOOT/BOOTX64.efi
						${UMOUNT_CMD} ${tmp_mp}
						${RMDIR_CMD} ${tmp_mp}
						${MDCONFIG_CMD} -d -u ${unit}
						${MKIMG_CMD} -s gpt -b ${TMP_DIR}/boot/pmbr -p efi:=${_efi_part} -p freebsd-boot:=${TMP_DIR}/boot/gptboot ${_swap_args} -p freebsd-ufs:=${dstdir}/${dstname}.part -o ${dstdir}/${dstname}
					else
						err 1 "${N1_COLOR}${CBSD_APP}: no such boot1.efi or loader.efi${N0_COLOR}"
					fi
				else
					${MKIMG_CMD} -s gpt -b ${TMP_DIR}/boot/pmbr -p freebsd-boot:=${TMP_DIR}/boot/gptboot ${_swap_args} -p freebsd-ufs:=${dstdir}/${dstname}.part -o ${dstdir}/${dstname}
				fi
				if [ -n "${freesize}" ]; then
					${TRUNCATE_CMD} -s+"${freesize}" ${dstdir}/${dstname}
					unit=$( ${MDCONFIG_CMD} -a -t vnode -f ${dstdir}/${dstname} )
					echo "U: ${unit}"
					${GPART_CMD} recover ${unit}
					if [ -n "${_swap_args}" ]; then
						${GPART_CMD} resize -i4 ${unit}
						${GROWFS_CMD} -y /dev/${unit}p4
						# suj?
						#/sbin/tunefs -j enable /dev/${unit}p4
						/sbin/tunefs -n enable /dev/${unit}p4
					else
						${GPART_CMD} resize -i3 ${unit}
						${GROWFS_CMD} -y /dev/${unit}p3
						# suj?
						#/sbin/tunefs -j enable /dev/${unit}p3
						/sbin/tunefs -n enable /dev/${unit}p3
					fi
					${MDCONFIG_CMD} -d -u ${unit}
				fi
				;;
			zfs)
				# deprecated, rewrite:
				create_img_for_dir ${data} ${dstdir}/${dstname}
				unit=$( ${MDCONFIG_CMD} -a -t vnode -f ${dstdir}/${dstname} 2>&1 )
				[ $? -ne 0 ] && err 1 "${N1_COLOR}${CBSD_APP}: mdconfig ${W1_COLOR}failed${N2_COLOR} ${unit}${N0_COLOR}"
				bhyve_zfs_install
				;;
		esac

		mynic=$( getnics-by-ip ip=0.0.0.0 2>/dev/null skip=bridge )
		[ -z "${mynic}" ] && mynic="em0"
		[ ${quiet} -eq 0 ] && show_bhyve_message
		#${MDCONFIG_CMD} -d -u ${unit}
		;;
	*)
		err 1 "${N1_COLOR}unknown media, valid: ${N2_COLOR}iso${N1_COLOR}, ${N2_COLOR}memstick ${N1_COLOR}or ${N2_COLOR}bhyve${N0_COLOR}"
esac

[ "${ver}" != "empty" ] && unmountfstab jroot=${path} fstab=${mount_fstab} > /dev/null 2>&1

jcleanup jname=${jname}

exit 0
