git: c41ba99779d0 - main - release/vm: partially support NO_ROOT

From: Brooks Davis <brooks_at_FreeBSD.org>
Date: Wed, 12 Mar 2025 21:07:04 UTC
The branch main has been updated by brooks:

URL: https://cgit.FreeBSD.org/src/commit/?id=c41ba99779d0431c37ac06a674e7744d15de8045

commit c41ba99779d0431c37ac06a674e7744d15de8045
Author:     Brooks Davis <brooks@FreeBSD.org>
AuthorDate: 2025-03-12 21:05:39 +0000
Commit:     Brooks Davis <brooks@FreeBSD.org>
CommitDate: 2025-03-12 21:05:39 +0000

    release/vm: partially support NO_ROOT
    
    For images that don't require QEMU, support NO_ROOT.  This entails:
     - Passing NO_ROOT down to mk-vmimage.sh (which sets it for
       installworld, etc)
     - Handling etcupdate bootstrapping
     - Adding assorted config file METALOG entries
     - Running makefs in the right directory and adding -D for dups
    
    The main gap in basic NO_ROOT support is package installation.  Each
    image type must also be updated to add METALOG entries for any files it
    adds.
    
    Reviewed by:    emaste
    Sponsored by:   DARPA, AFRL
    Differential Revision:  https://reviews.freebsd.org/D49320
---
 release/Makefile.vm         |  5 +++++
 release/tools/basic-ci.conf |  4 +++-
 release/tools/vmimage.subr  | 33 +++++++++++++++++++++++++++------
 3 files changed, 35 insertions(+), 7 deletions(-)

diff --git a/release/Makefile.vm b/release/Makefile.vm
index b711d7891f11..0dc7bdbe1fe5 100644
--- a/release/Makefile.vm
+++ b/release/Makefile.vm
@@ -108,6 +108,10 @@ QEMUTGT=emulator-portinstall
 QEMUTGT?=
 
 .if defined(WITH_CLOUDWARE) && !empty(WITH_CLOUDWARE) && !empty(CLOUDWARE)
+.if (defined(WITHOUT_QEMU) && !defined(NO_ROOT)) || \
+  (!defined(WITHOUT_QEMU) && defined(NO_ROOT))
+.error WITHOUT_QEMU requires NO_ROOT (and vice versa)
+.endif
 . for _CW in ${CLOUDWARE}
 .  if exists(${.CURDIR}/tools/${_CW:tl}.conf) && !defined(${_CW:tu}CONF)
 ${_CW:tu}CONF?=	${.CURDIR}/tools/${_CW:tl}.conf
@@ -126,6 +130,7 @@ cw-${_CW:tl}-${_FS}-${_FMT}: ${QEMUTGT}
 	env TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH} SWAPSIZE=${SWAPSIZE} \
 		QEMUSTATIC=${QEMUSTATIC} \
 		WITHOUT_QEMU=${WITHOUT_QEMU:Dtrue} \
+		NO_ROOT=${NO_ROOT:Dtrue} \
 		${.CURDIR}/scripts/mk-vmimage.sh \
 		-C ${.CURDIR}/tools/vmimage.subr -d ${.OBJDIR}/${.TARGET} -F ${_FS} \
 		-i ${.OBJDIR}/${_CW:tl}.${_FS}.${_FMT}.img -s ${VMSIZE} -f ${_FMT} \
diff --git a/release/tools/basic-ci.conf b/release/tools/basic-ci.conf
index 5acc04b1e530..12c9abb15fb1 100644
--- a/release/tools/basic-ci.conf
+++ b/release/tools/basic-ci.conf
@@ -21,6 +21,8 @@ beastie_disable="YES"
 loader_logo="none"
 console="comconsole,vidconsole"
 EOF
+	metalog_add_data ./boot/loader.conf
+
     cat <<EOF >> ${DESTDIR}/etc/ssh/sshd_config
 PermitRootLogin yes
 PasswordAuthentication yes
@@ -28,7 +30,7 @@ PermitEmptyPasswords yes
 UsePAM no
 EOF
 
-	touch ${DESTDIR}/firstboot
+	touch_firstboot
 
 	return 0
 }
diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr
index e7bd351c035c..c647097e8ced 100644
--- a/release/tools/vmimage.subr
+++ b/release/tools/vmimage.subr
@@ -37,6 +37,13 @@ cleanup() {
 	return 0
 }
 
+metalog_add_data() {
+	if [ -n "${NO_ROOT}" ]; then
+		echo "$1 type=file uname=root gname=wheel mode=0644" >> \
+		    ${DESTDIR}/METALOG
+	fi
+}
+
 vm_create_base() {
 
 	mkdir -p ${DESTDIR}
@@ -61,7 +68,14 @@ vm_install_base() {
 	etcupdate extract -B \
 		-M "TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}" \
 		-s ${WORLDDIR} -d ${DESTDIR}/var/db/etcupdate \
-		-L /dev/stdout
+		-L /dev/stdout ${NO_ROOT:+-N}
+	if [ -n "${NO_ROOT}" ]; then
+		# Reroot etcupdate's internal METALOG to the whole tree
+		sed -n 's,^\.,./var/db/etcupdate/current,p' \
+		    ${DESTDIR}/var/db/etcupdate/current/METALOG | \
+		    env -i LC_COLLATE=C sort >> ${DESTDIR}/METALOG
+		rm ${DESTDIR}/var/db/etcupdate/current/METALOG
+	fi
 
 	echo '# Custom /etc/fstab for FreeBSD VM images' \
 		> ${DESTDIR}/etc/fstab
@@ -73,16 +87,19 @@ vm_install_base() {
 		echo '/dev/gpt/swapfs  none    swap    sw      0       0' \
 			>> ${DESTDIR}/etc/fstab
 	fi
+	metalog_add_data ./etc/fstab
 
 	local hostname
 	hostname="$(echo $(uname -o) | tr '[:upper:]' '[:lower:]')"
 	echo "hostname=\"${hostname}\"" >> ${DESTDIR}/etc/rc.conf
+	metalog_add_data ./etc/rc.conf
 	if [ "${VMFS}" = zfs ]; then
 		echo "zfs_enable=\"YES\"" >> ${DESTDIR}/etc/rc.conf
 		echo "zpool_reguid=\"zroot\"" >> ${DESTDIR}/etc/rc.conf
 		echo "zpool_upgrade=\"zroot\"" >> ${DESTDIR}/etc/rc.conf
 		echo "kern.geom.label.disk_ident.enable=0" >> ${DESTDIR}/boot/loader.conf
 		echo "zfs_load=YES" >> ${DESTDIR}/boot/loader.conf
+		metalog_add_data ./boot/loader.conf
 	fi
 
 	return 0
@@ -191,11 +208,11 @@ buildfs() {
 
 	case "${VMFS}" in
 	ufs)
-		makefs ${MAKEFSARGS} -o label=rootfs -o version=2 -o softupdates=1 \
-			${VMBASE} ${DESTDIR}
+		cd ${DESTDIR} && makefs ${MAKEFSARGS} -o label=rootfs -o version=2 -o softupdates=1 \
+			${VMBASE} .${NO_ROOT:+/METALOG}
 		;;
 	zfs)
-		makefs -t zfs ${MAKEFSARGS} \
+		cd ${DESTDIR} && makefs -t zfs ${MAKEFSARGS} \
 			-o poolname=zroot -o bootfs=zroot/ROOT/default -o rootpath=/ \
 			-o fs=zroot\;mountpoint=none \
 			-o fs=zroot/ROOT\;mountpoint=none \
@@ -212,7 +229,7 @@ buildfs() {
 			-o fs=zroot/var/log\;setuid=off\;exec=off \
 			-o fs=zroot/var/mail\;atime=on \
 			-o fs=zroot/var/tmp\;setuid=off \
-			${VMBASE} ${DESTDIR}
+			${VMBASE} .${NO_ROOT:+/METALOG}
 		;;
 	*)
 		echo "Unexpected VMFS value '${VMFS}'"
@@ -276,7 +293,7 @@ vm_create_disk() {
 		WITH_UNIFIED_OBJDIR=yes \
 		make -C ${WORLDDIR}/stand -V .OBJDIR)"
 	BOOTFILES="$(realpath ${BOOTFILES})"
-	MAKEFSARGS="-s ${VMSIZE}"
+	MAKEFSARGS="-s ${VMSIZE} -D"
 
 	case "${TARGET}:${TARGET_ARCH}" in
 		amd64:amd64 | i386:i386)
@@ -345,3 +362,7 @@ vm_extra_create_disk() {
 	return 0
 }
 
+touch_firstboot() {
+	touch ${DESTDIR}/firstboot
+	metalog_add_data ./firstboot
+}