#!/usr/local/bin/cbsd
#v13.1.16
CBSDMODULE="sys"
MYARG=""
MYOPTARG="arch basename cmd_helper destdir qemu register_basename stable target_arch ver packages"
MYDESC="Install base-in-package FreeBSD base"
ADDHELP="
${H3_COLOR}Description${N0_COLOR}:

Install base/rootfs from pkg (base-in-packages) and register it and CBSD DB.
When destdir= used, registration in the CBSD DB will be skipped.

${H3_COLOR}Options${N0_COLOR}:

 ${N2_COLOR}arch=${N0_COLOR}              - <name>, use non-native architectures.
 ${N2_COLOR}basename=${N0_COLOR}          - Prefix for directory name, can be used for jail as alternative base.
 ${N2_COLOR}cmd_helper=${N0_COLOR}        - Run helper which will set a symlink to a stub for base files 
                      that are missing ( 1 - enabled, by default );
 ${N2_COLOR}destdir${N0_COLOR}            - <path> - alternative DESTDIR= path instead of ~cbsd/basejail/.
 ${N2_COLOR}qemu${N0_COLOR}               - '0' - copy (default) or '1' - do not copy the 
                     qemu emulator into base /bin;
 ${N2_COLOR}register_basename=${N0_COLOR} - <name> register with alternative/custom basename.
 ${N2_COLOR}stable=${N0_COLOR}            - 1 for RELENG_X.
 ${N2_COLOR}target_arch=${N0_COLOR}       - <name>, build non-native target arch.
 ${N2_COLOR}ver=${N0_COLOR}               - set version: '13.0', '13.1';
                      when version without minor version: e.g:
                     '13' or '12' - you will receive RELENG (stable=1), not release.

${H3_COLOR}Examples${N0_COLOR}:

 # cbsd install-pkg-world
 # cbsd install-pkg-world packages=\"FreeBSD-clang\"
 # cbsd install-pkg-world destdir=/tmp/test ver=14 cmd_helper=0 packages=\"FreeBSD-runtime\"

${H3_COLOR}See also${N0_COLOR}:

  cbsd buildworld --help
  cbsd bases --help
  cbsd register_base --help
  cbsd world --help
  cbsd repo --help

"

. ${subrdir}/nc.subr
readconf buildworld.conf
register_basename=
qemu=
opackages=
packages=
destdir=
cmd_helper=1
. ${cbsdinit}

[ -n "${packages}" ] && opackages="${packages}"

if [ -n "${qemu}" ]; then
	oqemu="${qemu}"
else
	qemu=1
fi

. ${subrdir}/universe.subr

over="${ver}"
oarch="${arch}"

# By default ver=current version
. ${subrdir}/build.subr

init_notify
init_target_arch
init_srcdir			# TODO: distribution in etcupdate tgz! not for stable version
init_supported_arch

if [ -n "${register_basename}" ]; then
	init_basedir -b ${register_basename}
else
	init_basedir
fi

#[ -x "${BASE_DIR}/bin/sh" ] &&  err 1 "${N1_COLOR}${CBSD_APP}: not empty, base already exist: ${N2_COLOR}${BASE_DIR}${N0_COLOR}"

[ -n "${destdir}" ] && BASE_DIR="${destdir}"
[ -z "${BASE_DIR}" ] && err 1 "${N1_COLOR}Empty BASE_DIR${N0_COLOR}"

[ ! -d "${BASE_DIR}" ] && ${MKDIR_CMD} -p ${BASE_DIR}
makelock ${BASE_DIR_LOCKFILE} "cleanup_bases"

# make base lock
echo $$ > ${BASE_DIR_LOCKFILE}

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

register_base arch=${arch} ver=${ver} source="install-pkg-world" auto_baseupdate=0 ${_basename_args}

base_status_is_maintenance_hard

# map amd64 -> x86_64 for DFLY
if [ "${platform}" = "DragonFly" ]; then
	err 1 "${N1_COLOR}${CBSD_APP}: base-in-pkg not supported yet for ${N2_COLOR}${platform}${N0_COLOR}"
	case "${arch}" in
		amd64)
			build_arch="x86_64"
			build_target_arch="x86_64"
			;;
	esac
else
	build_arch="${arch}"
	build_target_arch="${target_arch}"
fi

set -o errexit
readconf ${platform}-base_in_pkg.conf
readconf ${platform}-base_in_pkg-${ver}.conf

echo "${platform}-base_in_pkg-${ver}.conf"

# We need distribution first due to valid CRC sum for config via PKG
${ECHO} "${N1_COLOR}Fetching distribution archive...${N0_COLOR}"

# pkg set ignore ABI/non-interactive mode
major_ver=${ver%%.*}
ABI="${platform}:${major_ver}:${arch}"
export ABI=FreeBSD:${major_ver}:${arch}
export IGNORE_OSVERSION=yes
export ASSUME_ALWAYS_YES=yes
export ABI
eval base_in_pkg_repo_url="${base_in_pkg_repo_url}"

${FETCH_CMD} -o /tmp/distribution_${arch}_${target_arch}_${ver}.tgz  ${base_in_pkg_repo_url}/distribution_${arch}_${target_arch}_${ver}.tgz
ret=$?
if [ ${ret} -ne 0 ]; then
	err 1 "${N1_COLOR}fetch distribution archive failed: ${N2_COLOR}${base_in_pkg_repo_url}/distribution_${arch}_${target_arch}_${ver}.tgz${N0_COLOR}"
fi

if [ ! -r /tmp/distribution_${arch}_${target_arch}_${ver}.tgz ]; then
	err 1 "${N1_COLOR}fetch distribution archive failed: ${N2_COLOR}${base_in_pkg_repo_url}/distribution_${arch}_${target_arch}_${ver}.tgz${N0_COLOR}"
fi


cd /tmp
${TAR_CMD} xfz distribution_${arch}_${target_arch}_${ver}.tgz
ret=$?
if [ ${ret} -ne 0 ]; then
	${RM_CMD} -f distribution_${arch}_${target_arch}_${ver}.tgz
	err 1 "${N1_COLOR}unable to extract archive into /tmp: ${N2_COLOR}${base_in_pkg_repo_url}/distribution_${arch}_${target_arch}_${ver}.tgz${N0_COLOR}"
fi

${RM_CMD} -f distribution_${arch}_${target_arch}_${ver}.tgz

if [ ! -r /tmp/distribution_${arch}_${target_arch}_${ver}/COPYRIGHT ]; then
	[ -d /tmp/distribution_${arch}_${target_arch}_${ver} ] && ${RM_CMD} -rf /tmp/distribution_${arch}_${target_arch}_${ver}
	err 1 "${N1_COLOR}fetch/extract distribution archive failed: no such /COPYRIGHT file in ${N2_COLOR}${base_in_pkg_repo_url}/distribution_${arch}_${target_arch}_${ver}.tgz${N0_COLOR}"
fi

# to log?
${RSYNC_CMD} -avz /tmp/distribution_${arch}_${target_arch}_${ver}/ ${BASE_DIR}/ > /dev/null 2>&1
[ -d /tmp/distribution_${arch}_${target_arch}_${ver} ] && ${RM_CMD} -rf /tmp/distribution_${arch}_${target_arch}_${ver}

# Setup pkg
${MKDIR_CMD} -p ${BASE_DIR}/usr/share/keys/
${RSYNC_CMD} -avz /usr/share/keys/ ${BASE_DIR}/usr/share/keys/

# we need to use system/global path
[ ! -d ${BASE_DIR}/etc/pkg ] && ${MKDIR_CMD} -p ${BASE_DIR}/etc/pkg
${ECHO} "${N1_COLOR}Generate pkg.conf for base-in-packages v${ver}: ${N2_COLOR}${BASE_DIR}/etc/pkg/base-in-pkg.conf${N0_COLOR}"
${CAT_CMD} > ${BASE_DIR}/etc/pkg/base-in-pkg.conf <<EOF
# created by CBSD install-pkg-world
cbsd-base-in-pkg: {
	conservative_upgrade: no,
	priority: 10
	url: "${base_in_pkg_repo_url}",
	mirror_type: "none",
	enabled: yes
}
EOF

# save/restore old ?
[ ! -r ${BASE_DIR}/etc ] && ${MKDIR_CMD} ${BASE_DIR}/etc
${CAT_CMD} > ${BASE_DIR}/etc/resolv.conf <<EOF
nameserver 8.8.8.8              # CBSD makeresolv function
nameserver 8.8.4.4              # CBSD makeresolv function
EOF

echo "env SIGNATURE_TYPE=none IGNORE_OSVERSION=yes ASSUME_ALWAYS_YES=yes /usr/sbin/pkg -R ${BASE_DIR}/etc/pkg -r ${BASE_DIR} update -f -r cbsd-base-in-pkg"
env SIGNATURE_TYPE=none IGNORE_OSVERSION=yes ASSUME_ALWAYS_YES=yes /usr/sbin/pkg ${PKG_CMD} -R ${BASE_DIR}/etc/pkg -r ${BASE_DIR} update -f -r cbsd-base-in-pkg
ret=$?
if [ ${ret} -ne 0 ]; then
	err ${ret} "pkg failed: ${ret}"
fi

echo "env SIGNATURE_TYPE=none IGNORE_OSVERSION=yes ASSUME_ALWAYS_YES=yes /usr/sbin/pkg -R ${BASE_DIR}/etc/pkg -r ${BASE_DIR} -r ${BASE_DIR} install -y -r cbsd-base-in-pkg FreeBSD-runtime"
env SIGNATURE_TYPE=none IGNORE_OSVERSION=yes ASSUME_ALWAYS_YES=yes /usr/sbin/pkg -R ${BASE_DIR}/etc/pkg -r ${BASE_DIR} -r ${BASE_DIR} install -y -r cbsd-base-in-pkg FreeBSD-runtime
ret=$?
if [ ${ret} -ne 0 ]; then
	err ${ret} "pkg failed: ${ret}"
fi

[ -n "${opackages}" ] && base_in_pkg_list_active="${opackages}"

echo "env SIGNATURE_TYPE=none IGNORE_OSVERSION=yes ASSUME_ALWAYS_YES=yes /usr/sbin/pkg -R ${BASE_DIR}/etc/pkg -r ${BASE_DIR} install -y -r cbsd-base-in-pkg ${base_in_pkg_list_active}"
env SIGNATURE_TYPE=none IGNORE_OSVERSION=yes ASSUME_ALWAYS_YES=yes /usr/sbin/pkg -R ${BASE_DIR}/etc/pkg -r ${BASE_DIR} install -y -r cbsd-base-in-pkg ${base_in_pkg_list_active}
ret=$?
if [ ${ret} -ne 0 ]; then
	err ${ret} "pkg failed: ${ret}"
fi

# Remove .pkgsave file
${FIND_CMD} ${BASE_DIR}/ -mindepth 1 -type f -name *.pkgsave -delete

# Remove base-in-packages repo
${RM_CMD} -f ${BASE_DIR}/etc/pkg/base-in-pkg.conf

## ABI?
[ -z "${PKG_CMD}" ] && PKG_CMD="/usr/sbin/pkg"
if [ -x "${PKG_CMD}" ]; then
	env ASSUME_ALWAYS_YES=yes SIGNATURE_TYPE=none IGNORE_OSVERSION=yes ${PKG_CMD} -r ${BASE_DIR} install pkg
	[ -x ${BASE_DIR}/usr/local/sbin/pkg ] && ${CP_CMD} -a ${BASE_DIR}/usr/local/sbin/pkg ${BASE_DIR}/usr/sbin/
	[ -x ${BASE_DIR}/usr/local/sbin/pkg-static ] && ${CP_CMD} -a ${BASE_DIR}/usr/local/sbin/pkg-static ${BASE_DIR}/usr/sbin/
	env ASSUME_ALWAYS_YES=yes SIGNATURE_TYPE=none IGNORE_OSVERSION=yes ${PKG_CMD} -r ${BASE_DIR} remove -f pkg
else
	echo "No such pkg executable for bootstrap: [${PKG_CMD}]"
fi

# not in PKG ?
#${CP_CMD} -a /sbin/rcorder ${BASE_DIR}/sbin/

cbsdlogger NOTICE ${CBSD_APP}: install-pkg-world ended: ${MAKE_CMD} -C ${SRC_DIR} installworld DESTDIR=${BASE_DIR} TARGET=${build_arch} TARGET_ARCH=${build_target_arch}

# install: target directory `/usr/jails/basejail/base_amd64_amd64_14.0/etc/mail' does not exist
for i in /etc/mail /boot; do
	[ ! -d ${BASE_DIR}${i} ] && ${MKDIR_CMD} -p ${BASE_DIR}${i}
done

set +o errexit

[ -n "${oqemu}" ] && qemu="${oqemu}"
preparebase dst=${BASE_DIR} emulator=${emulator} qemu="${qemu}" init_freebsd_pkg=0

if [ ${cmd_helper} -eq 1 ]; then
	# CBSD distribution helper
	${FETCH_CMD} -o ${BASE_DIR}/bin/distribution ${base_in_pkg_repo_url}/distribution
	_ret=$?
	if [ ${_ret} -eq 0 ]; then
		if [ -r "${BASE_DIR}/bin/distribution" ]; then
			${CHMOD_CMD} +x ${BASE_DIR}/bin/distribution
			${ECHO} "${N1_COLOR}${CBSD_APP}: init CBSD distribtion helper for: ${N2_COLOR}${BASE_DIR}${N0_COLOR}"
			${BASE_DIR}/bin/distribution init "${BASE_DIR}"
		fi
	fi
fi

# Purge/Prune PKG cache
[ -d ${BASE_DIR}/var/cache/pkg ] && ${FIND_CMD} ${BASE_DIR}/var/cache/pkg/ -mindepth 1 -maxdepth 1 -delete
#echo "env SIGNATURE_TYPE=none ASSUME_ALWAYS_YES=yes /usr/sbin/pkg -r ${BASE_DIR} clean all"
#env SIGNATURE_TYPE=none ASSUME_ALWAYS_YES=yes /usr/sbin/pkg -r ${BASE_DIR} clean all

[ ! -f ${BASE_DIR}/bin/sh ] && err 1 "${N1_COLOR}No such /bin/sh in ${BASE_DIR}. Try to rebuild world${N0_COLOR}"

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

[ -z "${baseelf}" ] && baseelf="0"
[ -z "${destdir}" ] && register_base arch=${arch} ver=${ver} target_arch="${target_arch}" source="install-pkg-world" auto_baseupdate=0 ${_basename_args}

${RM_CMD} -f ${BASE_DIR_LOCKFILE}

exit 0
