From 2c784c51950418141a11add0d2682ca3c85fc6e6 Mon Sep 17 00:00:00 2001
From: Johannes Schauer Marin Rodrigues <josch@mister-muffin.de>
Date: Fri, 29 Mar 2024 02:03:35 +0100
Subject: [PATCH] switch from genext2fs to mkfs.ext4

Problems with genext2fs:

 - slow O(n^2) runtime
 - need to upgrade ext2 filesystems to ext4 on first boot
 - inode size of 128 disallows timestamps beyond 2038 or sub-second
   precision timestamps

Problems with mkfs.ext4:

 - not bit-by-bit reproducible across multiple invocations

The problems with mkfs.ext4 are solved once this PR is merged:

https://github.com/tytso/e2fsprogs/pull/118
---
 .gitlab-ci.yml |  2 +-
 mkimage.sh     | 68 ++++++++++++++++++++++++++++++++++----------------
 2 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 778c3ef..999ae0b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -30,7 +30,7 @@ build:
       fi
     fi
     apt update -o Acquire::AllowReleaseInfoChange=true -o quiet::ReleaseInfoChange=true
-    apt-get --no-install-recommends -y install mmdebstrap genext2fs ca-certificates e2fsprogs pigz git mount parted apt-utils libarchive-tools python3-apt
+    apt-get --no-install-recommends -y install mmdebstrap ca-certificates e2fsprogs pigz git mount parted apt-utils libarchive-tools python3-apt
     if [ ! -e /proc/sys/fs/binfmt_misc/status ]; then
       mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
     fi
diff --git a/mkimage.sh b/mkimage.sh
index 1a3a652..95795a7 100755
--- a/mkimage.sh
+++ b/mkimage.sh
@@ -78,7 +78,7 @@ case "$MIRROR" in
 esac
 
 # make sure build tools are installed
-set -- mmdebstrap genext2fs e2fsprogs git mount parted python3-apt
+set -- mmdebstrap e2fsprogs git mount parted python3-apt
 if [ "$(dpkg --print-architecture)" != arm64 ]; then
 	set -- "$@" arch-test qemu-user-static
 fi
@@ -93,10 +93,6 @@ if dpkg --compare-versions "$(dpkg-query --showformat='${Version}\n' --show mmde
 	echo "mmdebstrap version must be >= 0.8.4-1"
 	exit 1
 fi
-if dpkg --compare-versions "$(dpkg-query --showformat='${Version}\n' --show genext2fs)" lt "1.5.0-2"; then
-	echo "genext2fs version must be >= 1.5.0-2"
-	exit 1
-fi
 
 # if we are in a git repository and if SOURCE_DATE_EPOCH is not set, use the
 # timestamp of the latest git commit
@@ -226,6 +222,14 @@ set -- "$@" \
 	--customize-hook='rm "$1"/etc/resolv.conf'
 # copy out kernel and initrd for use with qemu
 set -- "$@" --customize-hook="download /vmlinuz kernel" --customize-hook="download /initrd.img initrd"
+# copy out contents of /boot
+set -- "$@" --customize-hook="tar-out /boot boot.tar"
+# choose the correct mode
+if [ "$(id -u)" = 0 ]; then
+	set -- "$@" --mode=root
+else
+	set -- "$@" --mode=unshare
+fi
 
 case "$DIST" in
 	testing)
@@ -239,12 +243,35 @@ case "$DIST" in
 		;;
 esac
 
-mmdebstrap "$@" target-userland.tar
+if [ "$(id -u)" = 0 ]; then
+	run_inside_userns() {
+		"$@"
+	}
+else
+	run_inside_userns() {
+		unshare --user --map-auto --map-user=65536 --map-group=65536 --keep-caps -- "$@"
+	}
+fi
+
+TEMPROOT=
+cleanup() {
+	if test -n "$TEMPROOT"; then
+		run_inside_userns rm -Rf "$TEMPROOT"
+	fi
+	rm -f boot.ext4 boot.tar root.ext4
+}
+trap cleanup EXIT
+# The default action for these signals does not invoke the EXIT trap.
+trap 'exit 1' HUP INT QUIT TERM
+TEMPROOT="$(mktemp -d)"
+
+mmdebstrap "$@" --format=directory --mode=unshare --skip=output/dev "$TEMPROOT"
 
 # create a common root partition from the above
 # this will be identical independent of the sysimage
-mmtarfilter --path-exclude='/boot/*' < target-userland.tar \
-	| genext2fs --volume-label reformsdroot --block-size 1024 --size-in-blocks $((ROOTSIZE*1024)) --bytes-per-inode 16384 --tarball - root.ext2
+run_inside_userns find "$TEMPROOT/boot/" -mindepth 1 -delete
+: >root.ext4
+run_inside_userns /sbin/mkfs.ext4 -L reformsdroot -d "$TEMPROOT" "root.ext4" "${ROOTSIZE}M"
 
 # system ---------------------------------------------------------
 
@@ -319,9 +346,9 @@ for SYSIMAGE in $SYSIMAGES; do
 		exit 1
 	fi
 	MACHINE="$(basename "$CONF" .conf)"
-	# FIXME: use --skip=tar-in/mknod once support for it is in stable
 	set -- --variant=custom --skip=update,setup,cleanup \
-		--setup-hook='mmtarfilter --path-exclude="/dev/*" --path-include=/dev/pts --path-include=/dev/shm < target-userland.tar | tar --numeric-owner --xattrs --xattrs-include="*" --directory "$1" --extract --file -' \
+		--skip=check/empty \
+		--setup-hook="tar-in boot.tar /" \
 		--customize-hook="upload ./$(basename "$DTBPATH" .dtb)-flash.bin /boot/flash.bin" \
 		--chrooted-customize-hook="
 			set -exu;
@@ -344,20 +371,18 @@ for SYSIMAGE in $SYSIMAGES; do
 				--chrooted-customize-hook='update-initramfs -u'
 			;;
 	esac
-	mmdebstrap "$@" '' - \
-	| mmtarfilter --path-exclude='*' --path-include=/boot \
-		--path-include='/boot/*' --strip-components=2 \
-	| genext2fs --volume-label reformsdboot --block-size 1024 \
-		--size-in-blocks $((BOOTSIZE*1024)) --bytes-per-inode 16384 \
-		--tarball - boot.ext2
+	mmdebstrap "$@" '' --format=directory --mode=unshare --skip=output/dev "$TEMPROOT"
+
+	: >boot.ext4
+	run_inside_userns /sbin/mkfs.ext4 -L reformsdboot -d "$TEMPROOT/boot" "boot.ext4" "${BOOTSIZE}M"
 
 	# make sure that the filesystem includes boot.scr
-	/usr/sbin/debugfs boot.ext2 -R "stat boot.scr" \
-		| sed 's/ \+/ /g' | grep --quiet "Type: regular Mode: 0644 Flags: 0x0"
+	/usr/sbin/debugfs boot.ext4 -R "stat boot.scr" \
+		| sed 's/ \+/ /g' | grep --quiet "Type: regular Mode: 0644 Flags: 0x"
 
-	dd if=root.ext2 of="$SYSIMAGE.img" seek=$((((BOOTSIZE+4)*1024*1024)/4194304)) bs=4194304
-	dd if=boot.ext2 of="$SYSIMAGE.img" seek=1 bs=4194304 conv=notrunc
-	rm boot.ext2
+	dd if=root.ext4 of="$SYSIMAGE.img" seek=$((((BOOTSIZE+4)*1024*1024)/4194304)) bs=4194304
+	dd if=boot.ext4 of="$SYSIMAGE.img" seek=1 bs=4194304 conv=notrunc
+	rm boot.ext4
 	truncate --size="+512" "$SYSIMAGE.img"
 	/sbin/parted -s "$SYSIMAGE.img" "mklabel msdos"
 	# reproducible disk signature
@@ -382,4 +407,3 @@ echo "MD5 checksums:" >&2
 for SYSIMAGE in $SYSIMAGES; do
 	md5sum "$SYSIMAGE.img" >&2
 done
-rm target-userland.tar root.ext2
-- 
GitLab