#!/bin/sh
# Re-generate external executable cmd macros:
# different platforms may have different full/realpaths
: ${distdir="/usr/local/cbsd"}
# MAIN
if [ -z "${workdir}" ]; then
	[ -z "${cbsd_workdir}" ] && . /etc/rc.conf
	[ -z "${cbsd_workdir}" ] && exit 0
	workdir="${cbsd_workdir}"
fi

[ ! -f "${distdir}/cbsd.conf" ] && exit 0

. ${distdir}/cbsd.conf

if [ -z "${workdir}" -o "${workdir}" = "(null)" ]; then
	. /etc/rc.conf
	[ -z "${cbsd_workdir}" ] && exit 0
	workdir="${cbsd_workdir}"
fi

CMD_FILE=${workdir}/cmd.subr

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

if [ -n "${PRE_CBSD_CMD_PATH}" ]; then
	PATH="${PRE_CBSD_CMD_PATH}:${PATH}"
fi
if [ -n "${POST_CBSD_CMD_PATH}" ]; then
	PATH="${PATH}:${POST_CBSD_CMD_PATH}"
fi

export PATH="${PATH}"

# Hardened/FreeBSD/DflyBSD-specific CMD
add_freebsd_cmd()
{
	# dpv is gone on FreeBSD 15.0

	MAIN_CMD="${MAIN_CMD} \
bzip2 \
chflags \
devfs \
etcupdate \
fetch \
getent \
ipfw \
cpuset \
geli \
growfs \
gpart \
idprio \
ifconfig \
jexec \
jot \
kenv \
kldload \
kldstat \
lockf \
login \
makefs \
mdconfig \
mkimg \
mkuzip \
mtree \
ngctl \
newfs \
newfs_msdos \
pciconf \
pw \
service \
sha256 \
sockstat \
rctl \
setfib \
ulimit \
uuencode \
valectl \
"
}

# DragonflyBSD-specific CMD
add_dragonfly_cmd()
{
	MAIN_CMD="${MAIN_CMD} \
chflags \
fetch \
hammer2 \
idprio \
ifconfig \
jexec \
jot \
kenv \
kldload \
kldstat \
lockf \
login \
mount_hammer2 \
mtree \
newfs \
service \
pciconf \
pw \
sha256 \
uuencode \
"
}

# Linux-specific CMD
add_linux_cmd()
{
	MAIN_CMD="${MAIN_CMD} \
chattr \
brctl \
wget \
flock \
losetup \
nft \
sha256sum \
ip \
ionice \
uuencode \
"
}

#  optional/feature command
OPTIONAL_CMD="\
acpidump \
bhyvectl \
bhyve \
buildah \
git \
jail \
pfctl \
ndp \
nvmmctl \
qemu-system-x86_64 \
zfs \
zpool \
xl"

# main cmd: generic command for all platform
MAIN_CMD="\
arp \
awk \
basename \
cat \
chown \
chmod \
chroot \
column \
cp \
cpio \
cut \
date \
dd \
df \
du \
dirname \
env \
find \
file \
grep \
gzip \
gunzip \
head \
hexdump \
host \
hostname \
id \
install \
kill \
killall \
ldd \
ln \
ls \
make \
mkdir \
mktemp \
mount \
mv \
nc \
nice \
pax \
ps \
ping \
pwd \
readlink \
realpath \
rm \
rmdir \
route \
rsync \
scp \
sed \
seq \
sort \
ssh \
ssh-keygen \
stat \
strings \
sudo \
sync \
sysctl \
stty \
sqlite3 \
tail \
tar \
tee \
timeout \
touch \
uname \
tr \
truncate \
umount \
uuidgen \
whoami \
xargs \
xz \
xzcat \
wc \
"

# check by FreeBSD version, since the misc/elf_tables may be absent on first init
case "${platform}" in
	Linux)
		_version=$( sysctl -n kernel.osrelease 2>/dev/null | cut -d "-" -f 1  | tr '.' '0' )
		;;
	NetBSD)
		_version=$( sysctl -n kern.osrevision 2>/dev/null )
		;;
	*)
		_version=$( sysctl -n kern.osreldate 2>/dev/null )
		if [ -z "${_version}" ]; then
			echo "unable to get sysctl kern.osreldate"
			exit 1
		fi
		;;
esac

case "${platform}" in
	DragonFly)
		add_dragonfly_cmd
		;;
	Linux)
		add_linux_cmd
		;;
	*)
		#FreeBSD|HardenedBSD|XigmaNAS)
		if [ ${_version} -lt 1300131 ]; then
			# https://svnweb.freebsd.org/base?view=revision&revision=r368045
			MAIN_CMD="${MAIN_CMD} ping6"
		fi
		add_freebsd_cmd
		;;
esac

truncate -s0 ${CMD_FILE}.tmp

cat > ${CMD_FILE}.tmp <<EOF
if [ ! "\$_CBSD_CMD_SUBR" ]; then
_CBSD_CMD_SUBR=1
###
EOF
	if [ $? -ne 0 ]; then
		echo "cmdboot: append error: ${CMD_FILE}.tmp"
		cat >> ${CMD_FILE}.tmp <<EOF
###
fi
EOF
		exit 1
	fi

MAIN_CMD=$( echo ${MAIN_CMD} | sort )
OPTIONAL_CMD=$( echo ${OPTIONAL_CMD} | sort )

for i in ${MAIN_CMD}; do
	mycmd=
	mycmd=$( which ${i} 2>/dev/null )

	if [ -z "${mycmd}" -a ! -x "${mycmd}" ]; then
		echo "cmdboot: no such executable, CBSD dependency/requirement: ${i}"
		cat >> ${CMD_FILE}.tmp <<EOF
###
fi
EOF
		exit 1
	fi
	MY_CMD=$( echo ${i} | tr '\-[:lower:]' '_[:upper:]' )
	MY_CMD="${MY_CMD}_CMD"

	echo "${MY_CMD}=\"${mycmd}\"" >> ${CMD_FILE}.tmp
done

for i in ${OPTIONAL_CMD}; do
	mycmd=
	mycmd=$( which ${i} 2>/dev/null )

	if [ -z "${mycmd}" -a ! -x "${mycmd}" ]; then
		feature=
		case "${i}" in
			bhyve*)
				feature="bhyve_feat"
				;;
			jail)
				feature="jail_feat"
				;;
			xl)
				feature="xen_feat"
				;;
		esac

		if [ -n "${feature}" ]; then
			if [ -h ${dbdir}/local.sqlite ]; then
				echo "    cmdboot: no such optional executable: ${i}, ${feature} disabled" 1>&2
				if [ -z "${SQLITE3_CMD}" ]; then
					SQLITE3_CMD=$( which sqlite3 )
					if [ -z "${SQLITE3_CMD}" ]; then
						echo "cmdboot: no such sqlite3 executable"
						exit 1
					fi
				fi
				${SQLITE3_CMD} ${dbdir}/local.sqlite "UPDATE local SET ${feature}='0'"
			fi
		fi
	fi

	MY_CMD=$( echo ${i} | tr '\-[:lower:]' '_[:upper:]' )
	MY_CMD="${MY_CMD}_CMD"

	echo "${MY_CMD}=\"${mycmd}\"" >> ${CMD_FILE}.tmp
done

# whiptail = light dialog ?
DIALOG_CMD=$( which cdialog || which dialog || which bsddialog )
[ -z "${DIALOG_CMD}" ] && err 1 "no such dialog (cdialog/dialog/bsddialog)"
echo "DIALOG_CMD=\"${DIALOG_CMD}\"" >> ${CMD_FILE}.tmp

cat >> ${CMD_FILE}.tmp <<EOF
###
fi
EOF

# test & compare & replace original file
/bin/sh -n ${CMD_FILE}.tmp
if [ $? -ne 0 ]; then
	echo "cmdboot: sh -n error: ${CMD_FILE}.tmp"
	exit 1
fi

if [ -r ${CMD_FILE} ]; then
	is_diff=$( diff ${CMD_FILE} ${CMD_FILE}.tmp )
	if [ -n "${is_diff}" ]; then
		mv ${CMD_FILE}.tmp ${CMD_FILE}
	else
		rm -f ${CMD_FILE}.tmp
	fi
else
	mv ${CMD_FILE}.tmp ${CMD_FILE}
fi

exit 0
