#!/usr/local/bin/cbsd
#v12.1.9
MYARG="action"
# action=list,get,put
# source=src,obj,base,kernel,img
MYOPTARG="arch basename fetchonly fromfile inter mode name newjname quiet platform register_basename runasap sources stable target_arch url useconfig usehelpers ver"
MYDESC="Working with CBSD Repository"
ADDHELP="
${H3_COLOR}Description${N0_COLOR}:

 Work with a remote repository to get resources (bases, images).
 Some images have configuration helpers. Use the 'usehelpers=1' parameter 
 to run this helper if you want to get a working service right away.

 hint: alternative way to get FreeBSD 'base.txz' or 'kernel.txz' is base-in-packages via 'cbsd install-pkg-world'.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}action=${N0_COLOR}            - can be: 'list', 'get', 'put';
 ${N2_COLOR}arch=${N0_COLOR}              - any for mode=list for show all arch (no for cur. arch only;
 ${N2_COLOR}fetchonly=${N0_COLOR}         - download only, do not process;
 ${N2_COLOR}fromfile=${N0_COLOR}          - load arguments from ascii file;
 ${N2_COLOR}inter=${N0_COLOR}             - 0 to prevent any questions and to accept answers by default;
 ${N2_COLOR}mode=${N0_COLOR}              - can be: 'check', 'upgrade';
 ${N2_COLOR}name=${N0_COLOR}              - specify name of resource (e.g. for sources=img);
 ${N2_COLOR}newjname=${N0_COLOR}          - for sources=img, for alternative jname;
 ${N2_COLOR}platform=${N0_COLOR}          - target platform, default: 'FreeBSD';
 ${N2_COLOR}register_basename=${N0_COLOR} - register with alternative/custom basename;
 ${N2_COLOR}runasap=${N0_COLOR}           - 0,1: when 1 - run a jail immediately (atomic jcreate+jstart);
 ${N2_COLOR}sources=${N0_COLOR}           - can be: src, obj, base, bhyve, kernel, img, helpers, modules;
 ${N2_COLOR}url=${N0_COLOR}               - specify URL sources, separated by comma for multiple values;
 ${N2_COLOR}usehelpers=${N0_COLOR}        - (default: 0 ) when 1, execute img helper when exist (boostrap.sh file);
 ${N2_COLOR}ver=${N0_COLOR}               - any for mode=list for show all version (no for cur. version only;

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd repo action=list sources=img [ver=any]
 # cbsd repo action=get sources=img name=pgadmin4 usehelpers=1
 # cbsd repo action=get sources=base arch=amd64 ver=bookworm platform=Linux

${H3_COLOR}See also${N0_COLOR}:

 cbsd images --help
 cbsd install-pkg-world --help

"

. ${subrdir}/nc.subr

url=
register_basename=
fetchonly=
runasap=
platform=
. ${cbsdinit}
[ -n "${platform}" ] && oplatform="${platform}"
[ -n "${runasap}" ] && orunasap="${runasap}"
[ -n "${fetchonly}" ] && ofetchonly="${fetchonly}"
[ -z "${fetchonly}" ] && fetchonly=0
. ${system}

# MAIN
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


origver="${ver}"
. ${subrdir}/build.subr
# prefered for ver in arg
[ "${ver}" != "${origver}" -a -n "${origver}" ] && ver=${origver}

if [ -z "${ver}" -o "${ver}" = "native" ]; then
	# ver=$( ${SYSCTL_CMD} -n kern.osrelease| ${CUT_CMD} -d - -f 1 )
	# we preffer uname as source, due to some environment have UNAME_r for overwrite version
	tmpver=$( ${UNAME_CMD} -r )
	ver=${tmpver%%-*}
	unset tmpver
fi

readconf buildworld.conf
. ${subrdir}/universe.subr
. ${subrdir}/fetch.subr

[ -f "${fromfile}" ] && . ${fromfile}

checkmd5()
{
	local _GOOD _OMD5 _RMD5 _i _FILE
	DIR=$1
	_GOOD=0

	for _i in $( ${FIND_CMD} ${DIR} -mindepth 1 -name *.md5 -type f -print); do
		_FILE=$( ${ECHO} ${_i} | ${SED_CMD} 's/\.md5//g' )
		_OMD5=$( ${CAT_CMD} ${_FILE}.md5 )
		_RMD5=$( ${CAT_CMD} ${_FILE} | ${miscdir}/cbsd_md5 )
		[ "${_RMD5}" != "${_OMD5}" ] && _GOOD=$((_GOOD + 1))
	done

	return ${_GOOD}
}

checkrepo()
{
	local _i

	for _i in ${repo}; do
		[ -z $1 ] && printf "${N1_COLOR}Check for repository${N0_COLOR}: ${N2_COLOR}${_i}${N0_COLOR} ..."
		if fetchme -q 1 -u "${_i}/cbsd.index"; then
			${CAT_CMD} "${TF}"
			exit 0
		else
			${ECHO} "${_i} Offline"
			exit 1
		fi
	done
}

register_fetched_base()
{
	local _basename_args=

	#idx platform name arch ver stable elf date
	baseelf=
	baseelf=$( ${miscdir}/elf_tables --ver ${BASE_DIR}/bin/sh 2>/dev/null )

	local source="${1}"
	[ -z "${source}" ] && source="unknown"

	[ -z "${baseelf}" ] && baseelf="0"
	[ -z "${TARGET_ARCH}" ] && TARGET_ARCH="${arch}"

	strpos --str="${ver}" --search="."

	pos=$?
	if [ ${pos} -eq 0 ]; then
		stable=1
	else
		stable=0
	fi

	if [ -n "${basename}" ]; then
		_basename_args="basename=\"${basename}\""
	fi
	if [ -n "${register_basename}" ]; then
		_basename_args="basename=\"${register_basename}\""
	fi

	[ -n "${oplatform}" ] && platform="${oplatform}"
	register_base arch=${arch} ver=${ver} target_arch=${TARGET_ARCH} stable=${stable} platform="${platform}" source="${source}" ${_basename_args}
}

register_fetched_source()
{
	local source="${1}"
	[ -z "${source}" ] && source="unknown"

	#todo: SCM

	strpos --str="${ver}" --search="."

	pos=$?
	if [ ${pos} -eq 0 ]; then
		stable=1
	else
		stable=0
	fi

	[ -n "${oplatform}" ] && platform="${oplatform}"
	register_source ver=${ver} stable=${stable} platform="${platform}" source="${source}"
}

getbase()
{
	local _srcmd5_found _src_found _majorver _release _rel_postfix
	local win_mirror win_rate t_size _basename_args
	local _mirror_num=0 _mirror_cur=0

	if [ -z "${basename}" ]; then
		BDIR="${basejailpref}_${arch}_${ver}"
		_basename_args=
	else
		BDIR="${basejailpref}_${basename}_${arch}_${ver}"
		_basename_args="basename=\"${basename}\""
	fi

	if [ -n "${url}" ]; then
		OIFS="${IFS}"
		IFS=","
		for i in ${url}; do
			if [ -z "${i}" ]; then
				BSDBASE_DISTSITE="${i}"
			else
				BSDBASE_DISTSITE="${BSDBASE_DISTSITE} ${i}"
			fi
		done
		IFS="${OIFS}"
	else
		case "${platform}" in
			DragonFly)
				# There is no DFLY bases. https://avalon.dragonflybsd.org/snapshots/x86_64/jails/ too old.
				URL_HIER="releases/DragonFly/${arch}/${target_arch}/${ver}"
				# https://dl.convectix.com/releases/amd64/x86_64/6.2/base.txz
				BSDBASE_DISTSITE="https://dl.convectix.com/${URL_HIER}/base.txz"
				;;
			FreeBSD)
				case "${ver}" in
					15*)
						# HEAD placed at /pub/FreeBSD/snapshots/amd64/XX.0-CURRENT/
						_release="snapshots"
						_rel_postfix="CURRENT"
						URL_HIER="${arch}/${target_arch}/15.0"
						;;
					*)
						# RELEASES placed at /pub/FreeBSD/releases/${URL_HIER}-RELEASE/base.txz"
						_release="releases"
						_rel_postfix="RELEASE"
						URL_HIER="${arch}/${target_arch}/${ver}"
						;;
				esac
				BSDBASE_DISTSITE="https://download.freebsd.org/ftp/${_release}/${URL_HIER}-${_rel_postfix}/base.txz http://ftp.freebsd.org/pub/FreeBSD/${_release}/${URL_HIER}-${_rel_postfix}/base.txz https://pub.allbsd.org/pub/FreeBSD/${_release}/${URL_HIER}-${_rel_postfix}/base.txz"
				;;
			HardenedBSD)
				# Assume HBSD always in stable=1: at the moment (2018-01-17) doesn't have
				# /hardenedbsd-X.Y- url. So, adduct ver version to major version for repo hier
				_majorver=${ver%%.*}
				case "${_majorver}" in
					15)
						# https://ci-01.nyi.hardenedbsd.org/pub/hardenedbsd/current/amd64/amd64/BUILD-LATEST/base.txz
						URL_HIER="current/${arch}/${target_arch}/BUILD-LATEST"
						;;
					*)
						URL_HIER="${_majorver}-stable/${arch}/${target_arch}/BUILD-LATEST"
						;;
				esac
				# https://hardenedbsd.org/content/mirrors
				BSDBASE_DISTSITE="https://mirror.laylo.io/pub/hardenedbsd/${URL_HIER}/base.txz https://ci-01.nyi.hardenedbsd.org/pub/hardenedbsd/${URL_HIER}/base.txz"
				;;
			Linux)
				URL_HIER="releases/Linux/${arch}/${ver}"
				BSDBASE_DISTSITE="https://dl.convectix.com/${URL_HIER}/base.txz"
				;;
		esac
	fi

	if [ -x "${BASE_DIR}/bin/sh" ]; then
		if [ ${upgrade} -eq 1 ]; then
			${RM_CMD} -f ${BASE_DIR_LOCKFILE}
			stderr 0 "${N1_COLOR}${CBSD_APP}: you already have ${ver}: ${N2_COLOR}${BASE_DIR}${N1_COLOR}. Use mode=upgrade for upgrade${N0_COLOR}"
		fi
		${CHFLAGS_CMD} -R noschg ${BASE_DIR}
	fi

	strpos --str="${ver}" --search="."

	pos=$?
	if [ ${pos} -eq 0 ]; then
		stable=1
	else
		stable=0
	fi

	init_target_arch

	trap "cleanup_bases" HUP INT ABRT BUS TERM EXIT
	[ -n "${oplatform}" ] && platform="${oplatform}"

	register_base arch=${arch} ver=${ver} target_arch=${TARGET_ARCH} stable=${stable} platform="${platform}" ${_basename_args}

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=repo elf="-" id=base${ver}-${arch}-${stable} platform=${platform} arch=${arch} targetarch=${targetarch} ver=${ver} stable="${stable}" ${_basename_args} date="-" status=1
	fi

	if [ -x "${BASE_DIR}/bin/sh" ]; then
		base_status_is_maintenance_soft
	else
		base_status_is_maintenance_hard
	fi

	win_mirror=
	win_rate=0
	t_size=0

	if [ "${fbsdrepo}" = "1" ]; then
		scan_fastest_mirror -s "${BSDBASE_DISTSITE}" -t 3
		iso_site="${FASTEST_SRC_MIRROR}"
	fi

	if [ "${fbsdrepo}" = "1" -a -z "${basename}" ]; then
		## Official fbsd repo
		${ECHO} "${N1_COLOR}Looking for official ${platform} mirror:${N0_COLOR}"
		ARCHIVE="${MYDIR}/base.txz"
		for MIRROR in ${iso_site}; do
			fetchme -u ${MIRROR} -o ${ARCHIVE}
			if [ $? -eq 0 ]; then
				break
			else
				[ -r ${ARCHIVE} ] && ${RM_CMD} -f ${ARCHIVE}
			fi
		done
		if [ -r ${ARCHIVE} ]; then
			[ ${quiet} -ne 1 ] && printf "\n${N1_COLOR}repo: extracting base...${N0_COLOR}\n"
			[ ! -d "${BASE_DIR}" ] && ${MKDIR_CMD} -p ${BASE_DIR}
			cd ${BASE_DIR}
			set -e
			${TAR_CMD} xfz ${ARCHIVE}
			set +e
			${RM_CMD} -f ${ARCHIVE}
			# fetch lib32 only for amd64
			if [ "${arch}" = "amd64" -a -z "${url}" ]; then
				if [ "${platform}" = "FreeBSD" ]; then
					BSDBASE_DISTSITE="https://download.freebsd.org/ftp/${_release}/${URL_HIER}-${_rel_postfix}/lib32.txz http://ftp.freebsd.org/pub/FreeBSD/${_release}/${URL_HIER}-${_rel_postfix}/lib32.txz https://pub.allbsd.org/pub/FreeBSD/${_release}/${URL_HIER}-${_rel_postfix}/lib32.txz"

					#BSDBASE_DISTSITE="$MIRROR/pub/FreeBSD/releases/${URL_HIER}-RELEASE/lib32.txz"
					ARCHIVE="${MYDIR}/lib32.txz"
					for i in ${BSDBASE_DISTSITE}; do
						fetchme -u ${i} -o ${ARCHIVE}
						if [ $? -eq 0 ]; then
							break
						else
							[ -r ${ARCHIVE} ] && ${RM_CMD} -f ${ARCHIVE}
						fi
					done
					if [ -r ${ARCHIVE} ]; then
						[ ${quiet} -ne 1 ] && printf "\n${N1_COLOR}Extracting lib32...${N0_COLOR}\n"
						cd ${BASE_DIR}
						set -e
						${TAR_CMD} xfz ${ARCHIVE}
						set +e
						${RM_CMD} -f ${ARCHIVE}
					else
						printf "${N2_COLOR} Lib32 not found${N0_COLOR}\n"
					fi
				fi
			fi

			[ -n "${oplatform}" ] && platform="${oplatform}"
			register_fetched_base ${MIRROR}

			case "${platform}" in
				FreeBSD)
					preparebase dst=${BASE_DIR} emulator=${emulator}
					etcupdate mode=extract default_obtain_etcupdate_method=index ver=${ver} force=1
					etcupdate mode=build default_obtain_etcupdate_method=index ver=${ver} force=1
					;;
				Linux)
					echo "preparebase dst=${BASE_DIR} emulator=${emulator} platform=Linux"
					preparebase dst=${BASE_DIR} emulator=${emulator} platform=Linux
					;;
			esac

			# CBSD QUEUE
			if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
				baseelf=
				baseelf=$( ${miscdir}/elf_tables --ver ${BASE_DIR}/bin/sh 2>/dev/null )
				date=$( ${DATE_CMD} +%s )
				[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=update id=base${ver}-${arch}-${stable} elf=${baseelf}  platform=${platform} ver=${ver} rev="${SCM_REV}" date="${date}" stable="${stable}" status=1
				[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=repo id=base${ver}-${arch}-${stable} status=2
			fi

			${ECHO} "${N1_COLOR}Done...${N0_COLOR}"
			return 0
		fi
		printf "${N2_COLOR} Not found${N0_COLOR}\n"
		### Official fbsd repo end ###
	fi

	# _srcmd5_found=0
	_src_found=0

	URL_HIER="${arch}/${target_arch}/${ver}"

	for MYREPO in ${repo}; do
		${ECHO} "${N1_COLOR}REPO: ${N2_COLOR}${MYREPO}${N0_COLOR}"
		MIRROR="${MYREPO}/releases/${URL_HIER}/mirror.html";
		fetchme -q1 -u ${MIRROR} -o ${TF}

		if [ $? -eq 0 ]; then
			MYREPO=$( ${CAT_CMD} ${TF} )
			${ECHO} "${N1_COLOR}found new mirror for ${ver}: ${N2_COLOR}${MYREPO}${N0_COLOR}"
		fi

		if [ -z "${basename}" ]; then
			${ECHO} "${N1_COLOR}Looking for: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/base.txz${N0_COLOR}"
			fetchme -o ${MYDIR}/base_${arch}_${target_arch}_${ver}.txz -u ${MYREPO}/releases/${URL_HIER}/base.txz

			if [ $? -ne 0 ]; then
				${ECHO} "${N1_COLOR}base not found: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/base.txz${N0_COLOR}"
				continue
			else
				_src_found=1
			fi
			_srcmd5_found=1
		else
			${ECHO} "${N1_COLOR}Looking for: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/base_${basename}.txz${N0_COLOR}"
			fetchme -o ${MYDIR}/base_${basename}_${arch}_${target_arch}_${ver}.txz -u ${MYREPO}/releases/${URL_HIER}/base_${basename}.txz

			if [ $? -ne 0 ]; then
				${ECHO} "${N1_COLOR}Base not found: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/base_${basename}.txz${N0_COLOR}"
				continue
			else
				_src_found=1
			fi

			_srcmd5_found=1
		fi

		[ ${_srcmd5_found} -eq 1 -a ${_src_found} -eq 1 ] && break
	done

	[ ${_src_found} -ne 1 ] && err 1 "${N1_COLOR}Not found data${N0_COLOR}"

	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Extracting...${N0_COLOR}"
	[ ! -d "${BASE_DIR}" ] && ${MKDIR_CMD} -p ${BASE_DIR}
	cd ${BASE_DIR}

	if [ -z "${basename}" ]; then
		set -e
		${TAR_CMD} xfz ${MYDIR}/base_${arch}_${target_arch}_${ver}.txz
		set +e
	else
		set -e
		${TAR_CMD} xfz ${MYDIR}/base_${basename}_${arch}_${target_arch}_${ver}.txz
		set +e
	fi

	case "${platform}" in
		FreeBSD)
			etcupdate mode=extract default_obtain_etcupdate_method=index ver=${ver} force=1
			etcupdate mode=build default_obtain_etcupdate_method=index ver=${ver} force=1
			;;
	esac

	register_fetched_base ${MIRROR}
	cleanup_bases

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		baseelf=
		baseelf=$( ${miscdir}/elf_tables --ver ${BASE_DIR}/bin/sh 2>/dev/null )
		date=$( ${DATE_CMD} +%s )
		[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=update id=base${ver}-${arch}-${stable} elf=${baseelf} ${_basename_args} platform=${platform} ver=${ver} rev="${SCM_REV}" date="${date}" stable="${stable}" status=1
		[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=repo id=base${ver}-${arch}-${stable} status=2
	fi

	${ECHO} "${N1_COLOR}Done...${N0_COLOR}"

	return 0
}

getobj()
{
	if [ -z "${basename}" ]; then
		DST="${srcdir}/obj_${arch}_${ver}"
	else
		DST="${srcdir}/obj_${basename}_${arch}_${ver}"
	fi

	for MYREPO in ${repo}; do
		${ECHO} "${N1_COLOR}REPO:${N2_COLOR}${MYREPO}${N0_COLOR}"
		if [ -z "${basename}" ]; then
			MIRROR="${MYREPO}/obj_${arch}_${ver}/mirror.html";
		else
			MIRROR="${MYREPO}/obj_${basename}_${arch}_${ver}/mirror.html";
		fi

		if [ -d "${DST}" ]; then
			[ ${upgrade} -eq 1 ] || err 1 "You already have ${ver}"
			removeobj ver=${ver} arch=${arch}
		fi

		fetchme -q1 -u ${MIRROR} -o ${TF}

		if [ $? -eq 0 ]; then
			MYREPO=$( ${CAT_CMD} ${TF} )
			${ECHO} "Found new mirror for ${basename}: ${MYREPO}"
		fi

		if [ -z "${basename}" ]; then
			fetchme -o ${MYDIR}/obj_${arch}_${ver}.txz -u ${MYREPO}/${DIR}/obj_${arch}_${ver}.txz
			[ $? -eq 0 ] || continue
			fetchme -q1 -o ${MYDIR}/obj_${arch}_${ver}.txz.md5 -u ${MYREPO}/${DIR}/obj_${arch}_${ver}.txz.md5
			[ $? -eq 0 ] || continue
		else
			fetchme -o ${MYDIR}/obj_${basename}_${arch}_${ver}.txz -u ${MYREPO}/${DIR}/obj_${basename}_${arch}_${ver}.txz
			[ $? -eq 0 ] || continue
			fetchme -q1 -o ${MYDIR}/obj_${basename}_${arch}_${ver}.txz.md5 -u ${MYREPO}/${DIR}/obj_${basename}_${arch}_${ver}.md5
			[ $? -eq 0 ] || continue
		fi
	done

	if [ -z "${basename}" ]; then
		[ ! -f "${MYDIR}/obj_${arch}_${ver}.txz.md5" -a ! -f "${MYDIR}/obj_${arch}_${ver}.txz" ] && err 1 "No sources found"
	else
		[ ! -f "${MYDIR}/obj_${basename}_${arch}_${ver}.txz.md5" -a ! -f "${MYDIR}/obj_${basename}_${arch}_${ver}.txz" ] && err 1 "No sources found"
	fi

	if checkmd5 ${MYDIR}; then
		${ECHO} "MD5sum correct."
	else
		err 1 "MD5sum incorrect."
	fi

	${RM_CMD} -f ${MYDIR}/obj_${arch}_${ver}.txz.md5

	[ ${quiet} -ne 1 ] && ${ECHO} "Extracting..."
	cd ${srcdir}
	set -e
	${TAR_CMD} xfz ${MYDIR}/obj_${arch}_${ver}.txz
	set +e
	${RM_CMD} -f ${MYDIR}/obj_${arch}_${ver}.txz
	${ECHO} "Done..."
}

getsrc()
{
	local _srcmd5_found _src_found _majorver _release _rel_postfix
	local win_mirror win_rate t_size BDIR
	local _mirror_num=0 _mirror_cur=0

	BDIR="${srcdir}/src_${ver}/src"

	if [ -r "${BDIR}/Makefile" ]; then
		[ ${upgrade} -eq 1 ] || err 1 "${N1_COLOR}You already have ${ver}: ${N2_COLOR}${BDIR}${N0_COLOR}"
	fi

	if [ -n "${url}" ]; then
		OIFS="${IFS}"
		IFS=","
		for i in ${url}; do
			if [ -z "${i}" ]; then
				BSDSRC_DISTSITE="${i}"
			else
				BSDSRC_DISTSITE="${BSDSRC_DISTSITE} ${i}"
			fi
		done
		IFS="${OIFS}"
	else
		case "${platform}" in
			DragonFly)
				err 1 "${N1_COLOR}${platform} unsupported yet${N0_COLOR}"
				;;
			FreeBSD)
				case "${ver}" in
					15*)
						# HEAD placed at /pub/FreeBSD/snapshots/amd64/XX.0-CURRENT/
						_release="snapshots"
						_rel_postfix="CURRENT"
						URL_HIER="${arch}/${target_arch}/15.0"
						;;
					*)
						# RELEASES placed at /pub/FreeBSD/releases/${URL_HIER}-RELEASE/src.txz"
						_release="releases"
						_rel_postfix="RELEASE"
						URL_HIER="${arch}/${target_arch}/${ver}"
						;;
				esac
				BSDSRC_DISTSITE="https://download.freebsd.org/ftp/${_release}/${URL_HIER}-${_rel_postfix}/src.txz http://ftp.freebsd.org/pub/FreeBSD/${_release}/${URL_HIER}-${_rel_postfix}/src.txz https://pub.allbsd.org/pub/FreeBSD/${_release}/${URL_HIER}-${_rel_postfix}/src.txz"
				;;
			HardenedBSD)
				# Assume HBSD always in stable=1: at the moment (2018-01-17) doesn't have
				# /hardenedbsd-X.Y- url. So, adduct ver version to major version for repo hier
				_majorver=${ver%%.*}
				case "${_majorver}" in
					15)
						# https://ci-01.nyi.hardenedbsd.org/pub/hardenedbsd/current/amd64/amd64/BUILD-LATEST/src.txz
						URL_HIER="current/${arch}/${target_arch}/BUILD-LATEST"
						;;
					*)
						URL_HIER="${_majorver}-stable/${arch}/${target_arch}/BUILD-LATEST"
						;;
				esac
				# https://hardenedbsd.org/content/mirrors
				BSDBASE_DISTSITE="https://mirror.laylo.io/pub/hardenedbsd/${URL_HIER}/src.txz https://ci-01.nyi.hardenedbsd.org/pub/hardenedbsd/${URL_HIER}/src.txz"
				;;
		esac
	fi

	strpos --str="${ver}" --search="."

	pos=$?
	if [ ${pos} -eq 0 ]; then
		stable=1
	else
		stable=0
	fi

	init_target_arch

	trap "cleanup_srcs" HUP INT ABRT BUS TERM EXIT
	[ -n "${oplatform}" ] && platform="${oplatform}"
	register_src ver=${ver} platform="${platform}"

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=repo elf="-" id=src${ver} platform=${platform} ver=${ver} stable="${stable}" date="-" status=1
	fi

	if [ -r "${BDIR}/Makefile" ]; then
		source_status_is_maintenance_soft
	else
		source_status_is_maintenance_hard
	fi

	win_mirror=
	win_rate=0
	t_size=0

	if [ "${fbsdrepo}" = "1" ]; then
		scan_fastest_mirror -s "${BSDSRC_DISTSITE}" -t 3
		iso_site="${FASTEST_SRC_MIRROR}"
	fi

	if [ "${fbsdrepo}" = "1" -a -z "${basename}" ]; then
		## Official fbsd repo
		${ECHO} "${N1_COLOR}Looking for official ${platform} mirror:${N0_COLOR}"
		ARCHIVE="${MYDIR}/src.txz"
		for MIRROR in ${iso_site}; do
			fetchme -u ${MIRROR} -o ${ARCHIVE}
			if [ $? -eq 0 ]; then
				break
			else
				[ -r ${ARCHIVE} ] && ${RM_CMD} -f ${ARCHIVE}
			fi
		done
		if [ -r ${ARCHIVE} ]; then
			[ ${quiet} -ne 1 ] && printf "\n${N1_COLOR}Extracting source...${N0_COLOR}\n"
			[ ! -d "${BDIR}" ] && ${MKDIR_CMD} -p ${BDIR}
			cd ${BDIR}
			set -e
			${TAR_CMD} xfz ${ARCHIVE}
			set +e
			${RM_CMD} -f ${ARCHIVE}
			# src.txz from official repo contain /usr path, check this
			if [ -d "${BDIR}/usr/src" ]; then
				${MV_CMD} ${BDIR}/usr/src ${BDIR}/src
				${RMDIR_CMD} ${BDIR}/usr
			fi
			register_fetched_source ${MIRROR}
			# CBSD QUEUE
			if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
				date=$( ${DATE_CMD} +%s )
				[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=update id=source${ver}-${stable} platform=${platform} ver=${ver} rev="${SCM_REV}" date="${date}" stable="${stable}" status=1
				[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=repo id=source${ver}-${stable} status=2
			fi

			${ECHO} "${N1_COLOR}Done...${N0_COLOR}"
			return 0
		fi
		printf "${N2_COLOR} Not found${N0_COLOR}\n"
		### Official fbsd repo end ###
	fi

	# _srcmd5_found=0
	_src_found=0

	for MYREPO in ${repo}; do
		${ECHO} "${N1_COLOR}REPO: ${N2_COLOR}${MYREPO}${N0_COLOR}"
		MIRROR="${MYREPO}/releases/${URL_HIER}/mirror.html";
		fetchme -q1 -u ${MIRROR} -o ${TF}

		if [ $? -eq 0 ]; then
			MYREPO=$( ${CAT_CMD} ${TF} )
			${ECHO} "${N1_COLOR}Found new mirror for ${ver}: ${N2_COLOR}${MYREPO}${N0_COLOR}"
		fi

		${ECHO} "${N1_COLOR}Looking for: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/src.txz${N0_COLOR}"
		fetchme -o ${MYDIR}/source_${ver}.txz -u ${MYREPO}/releases/${URL_HIER}/src.txz

		if [ $? -ne 0 ]; then
			${ECHO} "${N1_COLOR}source not found: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/src.txz${N0_COLOR}"
			continue
		else
			_src_found=1
		fi
		_srcmd5_found=1

		[ ${_srcmd5_found} -eq 1 -a ${_src_found} -eq 1 ] && break
	done

	[ ${_src_found} -ne 1 ] && err 1 "${N1_COLOR}Not found data${N0_COLOR}"

	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Extracting...${N0_COLOR}"
	[ ! -d "${BDIR}" ] && ${MKDIR_CMD} -p ${BDIR}
	cd ${BDIR}

	set -e
	${TAR_CMD} xfz ${MYDIR}/source_${ver}.txz
	set +e

	# src.txz from official repo contain /usr path, check this
	if [ -d "${BDIR}/usr/src" ]; then
		${MV_CMD} ${BDIR}/usr/src ${BDIR}/src
		${RMDIR_CMD} ${BDIR}/usr
	fi

	register_fetched_source ${MIRROR}
	cleanup_sources

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		date=$( ${DATE_CMD} +%s )
		[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=update id=source${ver}-${stable} platform=${platform} ver=${ver} rev="${SCM_REV}" date="${date}" stable="${stable}" status=1
		[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=repo id=source${ver}-${stable} status=2
	fi

	${ECHO} "${N1_COLOR}Done...${N0_COLOR}"

	return 0
}

getkernel()
{
	local _srcmd5_found _src_found _majorver _release _rel_postfix
	local win_mirror win_rate t_size
	local _mirror_num=0 _mirror_cur=0

	if [ -z "${basename}" ]; then
		BDIR="${basejailpref}_${arch}_${ver}"
	else
		BDIR="${basejailpref}_${basename}_${arch}_${ver}"
	fi

	if [ -n "${url}" ]; then
		OIFS="${IFS}"
		IFS=","
		for i in ${url}; do
			if [ -z "${i}" ]; then
				BSDKERNEL_DISTSITE="${i}"
			else
				BSDKERNEL_DISTSITE="${BSDKERNEL_DISTSITE} ${i}"
			fi
		done
		IFS="${OIFS}"
	else
		case "${platform}" in
			DragonFly)
				err 1 "${N1_COLOR}${platform} unsupported yet${N0_COLOR}"
				;;
			FreeBSD)
				case "${ver}" in
					15*)
						# HEAD placed at /pub/FreeBSD/snapshots/amd64/XX.0-CURRENT/
						_release="snapshots"
						_rel_postfix="CURRENT"
						URL_HIER="${arch}/${target_arch}/15.0"
						;;
					*)
						# RELEASES placed at /pub/FreeBSD/releases/${URL_HIER}-RELEASE/kernel.txz"
						_release="releases"
						_rel_postfix="RELEASE"
						URL_HIER="${arch}/${target_arch}/${ver}"
						;;
				esac
				BSDKERNEL_DISTSITE="https://download.freebsd.org/ftp/${_release}/${URL_HIER}-${_rel_postfix}/kernel.txz http://ftp.freebsd.org/pub/FreeBSD/${_release}/${URL_HIER}-${_rel_postfix}/kernel.txz https://pub.allbsd.org/pub/FreeBSD/${_release}/${URL_HIER}-${_rel_postfix}/kernel.txz"
				;;
			HardenedBSD)
				# Assume HBSD always in stable=1: at the moment (2018-01-17) doesn't have
				# /hardenedbsd-X.Y- url. So, adduct ver version to major version for repo hier
				_majorver=${ver%%.*}
				case "${_majorver}" in
					15)
						# https://ci-01.nyi.hardenedbsd.org/pub/hardenedbsd/current/amd64/amd64/BUILD-LATEST/kernel.txz
						URL_HIER="current/${arch}/${target_arch}/BUILD-LATEST"
						;;
					*)
						URL_HIER="${_majorver}-stable/${arch}/${target_arch}/BUILD-LATEST"
						;;
				esac
				# https://hardenedbsd.org/content/mirrors
				BSDBASE_DISTSITE="https://mirror.laylo.io/pub/hardenedbsd/${URL_HIER}/kernel.txz https://ci-01.nyi.hardenedbsd.org/pub/hardenedbsd/${URL_HIER}/kernel.txz"
				;;
		esac
	fi

	if [ -x "${KERNEL_DIR}/bin/sh" ]; then
		[ ${upgrade} -eq 1 ] || err 1 "${N1_COLOR}You already have ${ver}: ${N2_COLOR}${KERNEL_DIR}${N1_COLOR}. Use mode=upgrade for upgrade${N0_COLOR}"
		${CHFLAGS_CMD} -R noschg ${KERNEL_DIR}
	fi

	strpos --str="${ver}" --search="."

	pos=$?
	if [ ${pos} -eq 0 ]; then
		stable=1
	else
		stable=0
	fi

	init_target_arch
	trap "cleanup_kernels" HUP INT ABRT BUS TERM EXIT
	[ -n "${oplatform}" ] && platform="${oplatform}"
	register_kernel arch=${arch} ver=${ver} target_arch=${TARGET_ARCH} stable=${stable} platform="${platform}"

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=repo elf="-" id=kernel${ver}-${arch}-${stable} platform=${platform} arch=${arch} targetarch=${targetarch} ver=${ver} stable="${stable}" date="-" status=1
	fi

	if [ -x "${KERNEL_DIR}/boot/kernel/kernel" ]; then
		kernel_status_is_maintenance_soft
	else
		kernel_status_is_maintenance_hard
	fi

	win_mirror=
	win_rate=0
	t_size=0

	if [ "${fbsdrepo}" = "1" ]; then
		scan_fastest_mirror -s "${BSDKERNEL_DISTSITE}" -t 3
		iso_site="${FASTEST_SRC_MIRROR}"
	fi

	if [ "${fbsdrepo}" = "1" -a -z "${basename}" ]; then
		## Official fbsd repo
		${ECHO} "${N1_COLOR}Looking for official ${platform} mirror:${N0_COLOR}"
		ARCHIVE="${MYDIR}/kernel.txz"
		for MIRROR in ${iso_site}; do
			fetchme -u ${MIRROR} -o ${ARCHIVE}
			if [ $? -eq 0 ]; then
				break
			else
				[ -r ${ARCHIVE} ] && ${RM_CMD} -f ${ARCHIVE}
			fi
		done
		if [ -r ${ARCHIVE} ]; then
			[ ${quiet} -ne 1 ] && printf "\n${N1_COLOR}Extracting kernel...${N0_COLOR}\n"
			[ ! -d "${KERNEL_DIR}" ] && ${MKDIR_CMD} -p ${KERNEL_DIR}
			cd ${KERNEL_DIR}
			set -e
			${TAR_CMD} xfz ${ARCHIVE}
			set +e
			${RM_CMD} -f ${ARCHIVE}
			register_kernel ver=${ver} platform="${platform}" source="${MIRROR}"
			# CBSD QUEUE
			if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
				baseelf=
				baseelf=$( ${miscdir}/elf_tables --ver ${KERNEL_DIR}/bin/sh 2>/dev/null )
				date=$( ${DATE_CMD} +%s )
				[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=update id=kernel${ver}-${arch}-${stable} elf=${baseelf} platform=${platform} ver=${ver} rev="${SCM_REV}" date="${date}" stable="${stable}" status=1
				[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=repo id=kernel${ver}-${arch}-${stable} status=2
			fi

			${ECHO} "${N1_COLOR}Done...${N0_COLOR}"
			return 0
		fi
		printf "${N2_COLOR} Not found${N0_COLOR}\n"
		### Official fbsd repo end ###
	fi

	# _srcmd5_found=0
	_src_found=0

	for MYREPO in ${repo}; do
		${ECHO} "${N1_COLOR}REPO: ${N2_COLOR}${MYREPO}${N0_COLOR}"
		MIRROR="${MYREPO}/releases/${URL_HIER}/mirror.html";
		fetchme -q1 -u ${MIRROR} -o ${TF}

		if [ $? -eq 0 ]; then
			MYREPO=$( ${CAT_CMD} ${TF} )
			${ECHO} "${N1_COLOR}Found new mirror for ${ver}: ${N2_COLOR}${MYREPO}${N0_COLOR}"
		fi

		if [ -z "${basename}" ]; then
			${ECHO} "${N1_COLOR}Looking for: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/kernel.txz${N0_COLOR}"
			fetchme -o ${MYDIR}/kernel_${arch}_${target_arch}_${ver}.txz -u ${MYREPO}/releases/${URL_HIER}/kernel.txz

			if [ $? -ne 0 ]; then
				${ECHO} "${N1_COLOR}kernel not found: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/kernel.txz${N0_COLOR}"
				continue
			else
				_src_found=1
			fi
			_srcmd5_found=1
		else
			${ECHO} "${N1_COLOR}Looking for: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/kernel_${basename}.txz${N0_COLOR}"
			fetchme -o ${MYDIR}/kernel_${basename}_${arch}_${target_arch}_${ver}.txz -u ${MYREPO}/releases/${URL_HIER}/kernel_${basename}.txz

			if [ $? -ne 0 ]; then
				${ECHO} "${N1_COLOR}Kernel not found: ${N2_COLOR}${MYREPO}/releases/${URL_HIER}/kernel_${basename}.txz${N0_COLOR}"
				continue
			else
				_src_found=1
			fi

			_srcmd5_found=1
		fi

		[ ${_srcmd5_found} -eq 1 -a ${_src_found} -eq 1 ] && break
	done

	[ ${_src_found} -ne 1 ] && err 1 "${N1_COLOR}Not found data${N0_COLOR}"

	[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}extracting...${N0_COLOR}"
	[ ! -d "${KERNEL_DIR}" ] && ${MKDIR_CMD} -p ${KERNEL_DIR}
	cd ${KERNEL_DIR}

	if [ -z "${basename}" ]; then
		set -e
		${TAR_CMD} xfz ${MYDIR}/kernel_${arch}_${target_arch}_${ver}.txz
		set +e
	else
		set -e
		${TAR_CMD} xfz ${MYDIR}/kernel_${basename}_${arch}_${target_arch}_${ver}.txz
		set +e
	fi

	register_kernel arch=${arch} ver=${ver} target_arch=${TARGET_ARCH} stable=${stable} platform="${platform}"
	cleanup_kernels

	# CBSD QUEUE
	if [ "${mod_cbsd_queue_enabled}" = "YES" -a -z "${MOD_CBSD_QUEUE_DISABLED}" ]; then
		baseelf=
		baseelf=$( ${miscdir}/elf_tables --ver ${KERNEL_DIR}/bin/sh 2>/dev/null )
		date=$( ${DATE_CMD} +%s )
		[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=update id=kernel${ver}-${arch}-${stable} elf=${baseelf}  platform=${platform} ver=${ver} rev="${SCM_REV}" date="${date}" stable="${stable}" status=1
		[ -n "${cbsd_repo_queue_name}" ] && ${cbsd_queue_backend} cbsd_queue_name=${cbsd_repo_queue_name} cmd=repo id=kernel${ver}-${arch}-${stable} status=2
	fi

	${ECHO} "${N1_COLOR}done...${N0_COLOR}"

	return 0
}

# todo: determine for schema/prefix to support full url, e.g:
# cbsd repo .. name=vmagent     = $REPO/vmagent
#  or
# cbsd repo .. name=http[s]://a.b.c/xxx.img = http[s]://a.b.c/xxx.img
getimg()
{
	local URL_HIER DST _ret _size _md5

	[ -z "${newjname}" ] && newjname="${name}"

	DST="${importdir}/${newjname}.img"
	URL_HIER="${arch}/${target_arch}/${ver}/${name}"

	if [ -f "${DST}" ]; then
		getyesno "You already have ${DST}. Remove them?"
		if [ $? -eq 0 -o $? -eq 3 ]; then
			${RM_CMD} -f ${DST}
		else
			err 1 "${N1_COLOR}You already have: ${N2_COLOR}${DST}${N0_COLOR}"
		fi
	fi

	jstatus jname=${newjname} > /dev/null 2>&1
	[ $? -ne 0 ] && err 1 "${N1_COLOR}You already have ${N2_COLOR}${newjname}${N1_COLOR} jail. Remove it or use ${N2_COLOR}newjname=${N0_COLOR}"

	for MYREPO in ${repo}; do
		${ECHO} "${N1_COLOR}REPO:${N2_COLOR} ${MYREPO}" 1>&2
		MIRROR="${MYREPO}/img/${URL_HIER}/mirror.html"
		fetchme -q1 -u ${MIRROR} -o ${TF}

		if [ $? -eq 0 ]; then
			MYREPO=$( ${CAT_CMD} ${TF} )
			${ECHO} "${N1_COLOR}Found new mirror for ${name} ${N0_COLOR}: ${MYREPO}" 1>&2
		fi

		${ECHO} "${N1_COLOR}Fetching ${name} jail: ${N2_COLOR}${MYREPO}/${DIR}${N1_COLOR}${N0_COLOR}" 1>&2
		fetchme -o ${DST} -u ${MYREPO}/img/${URL_HIER}/${name}.img
		_ret=$?
		[ ${_ret} -eq 0 -a -s ${MYREPO}/img/${URL_HIER}/${name}.img ] && break
	done

	if [ -s ${DST} ]; then
		_size=$( ${STAT_CMD} -f %z ${DST} 2>/dev/null )
		_md5=$( ${miscdir}/cbsd_md5 "${MYREPO}/img/${URL_HIER}/${name}.img" )
		_err=$( cbsdsqlrw images "INSERT INTO images ( md5,name,path,source,created,emulator,md5,size ) VALUES ( \"${_md5}\", \"${name}\", \"${DST}\", \"${MYREPO}/img/${URL_HIER}/${name}.img\", \"now\", \"jail\", \"${_size}\" )" )
		echo $?
		echo "pull ok: ${_err}"
	else
		[ ! -f "${DST}" ] && err 1 "No such remote file or network problem"
	fi
	return ${_ret}
}

getbhyve()
{
	local URL_HIER DST

	[ -z "${name}" ] && err 1 "${N1_COLOR}Empty name=${N0_COLOR}"

	[ -z "${newjname}" ] && newjname="${name}"

	DST="${importdir}/${newjname}.img"

	if [ -f "${DST}" ]; then
		getyesno "You already have ${DST}. Remove them?"
		if [ $? -eq 0 -o $? -eq 3 ]; then
			${RM_CMD} -f ${DST}
		else
			err 1 "${N1_COLOR}You already have: ${N2_COLOR}${DST}${N0_COLOR}"
		fi
	fi

	jstatus jname=${newjname} > /dev/null 2>&1
	[ $? -ne 0 ] && err 1 "${N1_COLOR}You already have ${N2_COLOR}${newjname}${N1_COLOR} vm."

	for MYREPO in ${repo}; do
		${ECHO} "${N1_COLOR}REPO:${N2_COLOR} ${MYREPO}"
		MIRROR="${MYREPO}/bhyve/${name}/mirror.html"
		fetchme -q1 -u ${MIRROR} -o ${TF}

		if [ $? -eq 0 ]; then
			MYREPO=$( ${CAT_CMD} ${TF} )
			${ECHO} "${N1_COLOR}Found new mirror for ${name} ${N0_COLOR}: ${MYREPO}"
		fi

		${ECHO} "${N1_COLOR}Fetching ${name} jail: ${N2_COLOR}${MYREPO}/${DIR}${N1_COLOR}${N0_COLOR}"
		fetchme -o ${DST} -u ${MYREPO}/bhyve/${name}.img

		[ $? -eq 0 ] || continue
	done

	[ ! -f "${DST}" ] && err 1 "No such remote file or network problem"
}

gethelpers()
{
	DST="${sharedir}/helpers"

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

	MIRROR="https://boot.convectix.com/helpers"

	if [ -z "${name}" ]; then
		fetchme -q1 -u ${MIRROR}/helpersls -o ${ftmpdir}/helpers.$$.list
		[ $? -ne 0 ] && err 1 "${N1_COLOR}Error fetching for: ${N2_COLOR}helper list${N0_COLOR}"
		for i in $( ${CAT_CMD} ${ftmpdir}/helpers.$$.list ); do
			${ECHO} "${N1_COLOR}Get helpers: ${N2_COLOR}${i}${N0_COLOR}"
			if [ "${mode}" = "upgrade" ]; then
				repo action=get sources=helpers name=${i} mode=upgrade
			else
				repo action=get sources=helpers name=${i}
			fi
		done
		${RM_CMD} -f ${ftmpdir}/helpers.$$.list
		exit 0
	fi

	[ ! -d "${tmpdir}/helpers" ] && ${MKDIR_CMD} -p ${tmpdir}/helpers
	fetchme -q1 -u ${MIRROR}/${name}.tgz -o ${tmpdir}/helpers/helpers_${name}.$$.tgz

	if [ $? -eq 0 ]; then
		if [ -d "${DST}/${name}" -a "${mode}" = "upgrade" ]; then
			rm -rf $DST/${name}
		elif [ -d "${DST}/${name}" ]; then
			${RM_CMD} -f ${tmpdir}/helpers/helpers_${name}.$$.tgz
			${RMDIR_CMD} ${tmpdir}/helpers
			err 1 "${N1_COLOR}Helpers already exist: ${N2_COLOR}${name}${N1_COLOR}. Use mode=upgrade for upgrading.${N0_COLOR}"
		fi
		${MKDIR_CMD} ${DST}/${name}
		set -e
		${TAR_CMD} xfz ${tmpdir}/helpers/helpers_${name}.$$.tgz -C ${DST}/${name}
		set +e
		${RM_CMD} -f ${tmpdir}/helpers/helpers_${name}.$$.tgz
	fi

	${RMDIR_CMD} ${tmpdir}/helpers
}

getmodules()
{
	DST="${moduledir}"

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

	MIRROR="https://boot.convectix.com/modules"

	if [ -z "${name}" ]; then
		fetchme -q1 -u ${MIRROR}/modulesls -o ${ftmpdir}/modules.$$.list
		[ $? -ne 0 ] && err 1 "${N1_COLOR}Error fetching for: ${N2_COLOR}modules list${N0_COLOR}"
		for i in $( ${CAT_CMD} ${ftmpdir}/modules.$$.list ); do
			${ECHO} "${N1_COLOR}Get modules: ${N2_COLOR}${i}${N0_COLOR}"
			if [ "${mode}" = "upgrade" ]; then
				repo action=get sources=modules name=${i} mode=upgrade
			else
				repo action=get sources=modules name=${i}
			fi
		done
		${RM_CMD} -f ${ftmpdir}/modules.$$.list
		exit 0
	fi

	[ ! -d "${tmpdir}/modules" ] && ${MKDIR_CMD} -p ${tmpdir}/modules
	fetchme -q1 -u ${MIRROR}/${name}.tgz -o ${tmpdir}/modules/modules_${name}.$$.tgz

	if [ $? -eq 0 ]; then
		if [ -d "${DST}/${name}" -a "${mode}" = "upgrade" ]; then
			${RM_CMD} -rf $DST/${name}
		elif [ -d "${DST}/${name}" ]; then
			${RM_CMD} -f ${tmpdir}/modules/modules_${name}.$$.tgz
			${RMDIR_CMD} ${tmpdir}/modules
			err 1 "${N1_COLOR}modules already exist: ${N2_COLOR}${name}${N1_COLOR}. Use mode=upgrade for upgrading.${N0_COLOR}"
		fi
		${MKDIR_CMD} ${DST}/${name}
		set -e
		${TAR_CMD} xfz ${tmpdir}/modules/modules_${name}.$$.tgz -C ${DST}/${name}
		set +e
		${RM_CMD} -f ${tmpdir}/modules/modules_${name}.$$.tgz
	fi

	${RMDIR_CMD} ${tmpdir}/modules
}

#### MAIN ####
[ -z "${quiet}" ] && quiet=0
[ -z "${upgrade}" ] && upgrade=0
[ -z "${usehelpers}" ] && usehelpers="0"
[ -z "${useconfig}" ] && useconfig="1"

TF="${ftmpdir}/test.$$"
MYDIR="${tmpdir}/src.$$"
[ -z "${inter}" ] && inter=1

[ -z "${action}" ] && err 1 "Give me action"

case "${mode}" in
	"upgrade")
		upgrade=1
		;;
esac

init_target_arch
init_supported_arch

case "${action}" in
	ping)
		if [ $quiet -eq 1 ]; then
			checkrepo quiet
		else
			checkrepo
		fi
		;;
	list|ls)
		case "${sources}" in
			bhyve|img)
				;;
			*)
				err 1 "${N1_COLOR}${CBSD_APP}: unknown sources, valid: ${N2_COLOR}'bhyve','img'${N0_COLOR}"
				;;
		esac
		for i in ${repo}; do
			if fetchme -q 1 -u "${i}/${sources}ls.v2"; then
				[ ${quiet} -ne 1 ] && ${ECHO} "${N1_COLOR}Available sources on ${N2_COLOR}$i:${N0_COLOR}" 1>&2
				case "${sources}" in
					"bhyve")
						${CAT_CMD} ${TF}
						;;
					img)
						if [ "${ver}" = "any" ]; then
							ver="[[:alnum:]]"
						else
							[ -z "${ver}" ] && ver=$( ${SYSCTL_CMD} -n kern.osrelease | ${CUT_CMD} -d "-" -f1 )
						fi
						if [ "${arch}" = "any" ]; then
							arch="[[:alnum:]]"
						else
							if [ -z "${arch}" ]; then
								arch=$( ${SYSCTL_CMD} -n hw.machine_arch )
								[ "${arch}" = "x86_64" ] && arch="amd64"
							fi
						fi
						${GREP_CMD} -E ${arch}_${ver} ${TF} | ${SORT_CMD} -n -k 1 | ${CUT_CMD} -d "|" -f2-9 | ${COLUMN_CMD} -t -s '|' 
					;;
					*)
						err 1 "${N1_COLOR}${CBSD_APP}: unknown sources, valid: ${N2_COLOR}'bhyve','img'${N0_COLOR}"
				esac
				${RM_CMD} -f ${TF}
			fi
		done
		;;
	"get")
		[ -z "${sources}" ] && err 1 "Give me sources"
		case "${sources}" in
			"src")
				init_basedir
				init_kerneldir
				DIR="src_${ver}"
				DST="${srcdir}/src_${ver}"
				LOCKFILE=${DST}.lock
				makelock ${LOCKFILE} "${RM_CMD} -f ${TF}; ${RM_CMD} -rf ${MYDIR}" safe
				${MKDIR_CMD} -p ${MYDIR}
				getsrc
				;;
			"base")
				# LOCKFILE=${SRC}.lock
				# makelock $LOCKFILE "${RM_CMD} -f ${TF}; ${RM_CMD} -rf ${MYDIR}" safe
				if [ -n "${register_basename}" ]; then
					init_basedir -b ${register_basename}
				else
					init_basedir
				fi
				init_kerneldir
				# make base lock
				echo $$ > ${BASE_DIR_LOCKFILE}
				trap "${RM_CMD} -f ${TF} ${BASE_DIR_LOCKFILE}; ${RM_CMD} -rf ${MYDIR}"
				${MKDIR_CMD} -p ${MYDIR}
				getbase
				;;
			"obj")
				if [ -z "${basename}" ]; then
					DIR="obj_${arch}_${ver}";
				else
					DIR="obj_${basename}_${arch}_${ver}";
				fi
				init_basedir
				init_kerneldir
				SRC="${srcdir}/src_${ver}"
				LOCKFILE=${SRC}.lock
				makelock $LOCKFILE "${RM_CMD} -f ${TF}; ${RM_CMD} -rf ${MYDIR}" safe
				${MKDIR_CMD} -p ${MYDIR}
				getobj
				;;
			"kernel")
				# [ -z "${name}" ] && name="GENERIC"
				# LOCKFILE=${SRC}.lock
				# makelock $LOCKFILE "${RM_CMD} -f ${TF}; ${RM_CMD} -rf ${MYDIR}" safe
				init_basedir
				init_kerneldir
				trap "${RM_CMD} -f ${TF}; ${RM_CMD} -rf ${MYDIR}"
				${MKDIR_CMD} -p ${MYDIR}
				getkernel
				;;
			img)
				[ -z "${name}" ] && err 1 "Give me name"
				LOCKFILE="${jaildir}/${name}.lock"
				makelock ${LOCKFILE} "${RM_CMD} -f ${TF}; ${RM_CMD} -rf ${MYDIR}"
				${MKDIR_CMD} -p ${MYDIR}
				getimg
				ret=$?
				[ ${fetchonly} -eq 1 ] && exit ${ret}
				if [ "${usehelpers}" = "1" ]; then
					${ECHO} "${N1_COLOR}Use img helpers: ${N2_COLOR}yes${N0_COLOR}"
					# && gethelpers ${name} ${name}
				else
					${ECHO} "${N1_COLOR}Use img helpers: ${N2_COLOR}no${N0_COLOR}"
				fi
				${ECHO} "${N1_COLOR}Done... Importing...${N0_COLOR}"
				if [ -n "${newjname}" ]; then
					name="${newjname}"
					jimport jname=${name} newjname="${name}"
				else
					jimport jname=${name}
				fi
				if [ -f "${importdir}/${name}.img" ]; then
					${ECHO} "${N1_COLOR}Import complete${N0_COLOR}"
					getyesno "Do you want to remove source image ${importdir}/${name}.img ?"
					[ $? -eq 0 -o $? -eq 3 ] && ${RM_CMD} -f ${importdir}/${name}.img
				fi

				if [ "${usehelpers}" = "1" ]; then
					if [ -r ${jailsysdir}/${name}/bin/bootstrap.sh -a -f ${jailsysdir}/${name}/bin/forms.sqlite ]; then
						jname="${name}"
						. ${subrdir}/rcconf.subr
						. ${subrdir}/jcreate.subr
						export_jail_data_for_external_hook
						imghelper bootstrap=${jailsysdir}/${jname}/bin/bootstrap.sh formfile=${jailsysdir}/${jname}/bin/forms.sqlite jname=${jname}
					elif [ -x ${jailsysdir}/${name}/bin/bootstrap.sh ]; then
						jname="${name}"
						${ECHO} "${N1_COLOR}Exec img helpers: ${N2_COLOR}${jailsysdir}/${name}/bin/bootstrap.sh${N0_COLOR}"
						oname="${name}"
						. ${subrdir}/rcconf.subr
						. ${subrdir}/jcreate.subr
						# restore
						name="${oname}"
						export_jail_data_for_external_hook
						${jailsysdir}/${jname}/bin/bootstrap.sh
					fi
				fi
				jset jname=${name} ip4_addr="DHCP"
				if [ -f "${jailsysdir}/${jname}/jail-message" ]; then
					${CAT_CMD} "${jailsysdir}/${jname}/jail-message"
				fi
#				[ ${inter} -ne 0 -a "${useconfig}" = "1" ] && jsetup-tui jname=${name} repo ip4_addr interface astart host_hostname
#				[ ${inter} -ne 0 -a "${useconfig}" = "1" ] && jsetup-tui jname=${name} ip4_addr interface astart host_hostname
				[ -n "${orunasap}" ] && runasap="${orunasap}"
				[ "${runasap}" = "1" ] && jstart jname=${name}
				;;
			"helpers")
				gethelpers
				;;
			modules)
				getmodules
				;;
			bhyve)
				getbhyve
				${ECHO} "${N1_COLOR}Done... Importing...${N0_COLOR}"
				if [ -n "${newjname}" ]; then
					name="${newjname}"
					bimport jname=${name} newjname="${name}"
				else
					bimport jname=${name}
				fi
				if [ -f "${importdir}/${name}.img" ]; then
					${ECHO} "${N1_COLOR}Import complete${N0_COLOR}"
					getyesno "Do you want to remove source image ${importdir}/${name}.img ?"
					[ $? -eq 0 -o $? -eq 3 ] && ${RM_CMD} -f ${importdir}/${name}.img
				fi
				;;
			*)
				err 1 "${N1_COLOR}Unknown sources: ${N2_COLOR}${sources}${N0_COLOR}"
				;;
		esac ## END of source case
		;;
esac ## END of action case

exit 0
