#!/bin/bash
# The end-to-end check for an erofs root on a 16K page size device, which is
# the combination the vendored mkfs.erofs exists for and the one no other
# test here reaches. config/trixie-minbase-ab.yaml selects the rpi5 device,
# whose rpi-linux-2712 layer forces linux page_size to 16384, and the
# image-rota layout, whose rootfs_type defaults to erofs and passes
# -b ${IGconf_linux_page_size} to mkfs.erofs. bookworm-minbase-ab.yaml pairs
# the same two layers, so either would do; this one tracks the suite the
# package is built for.
#
# The image is arm64, so a non-arm64 host needs aarch64 registered with
# binfmt_misc. It also needs the archive and the privileges mmdebstrap wants
# for its mount namespace, hence needs-internet and isolation-machine.
# Skippable: an environment that cannot offer those is a skip, not a failure.
set -uo pipefail

CONFIG=/usr/share/rpi-image-gen/config/trixie-minbase-ab.yaml
TMP=${AUTOPKGTEST_TMP:-$(mktemp -d)}
SKIP=77

[ -f "$CONFIG" ] || {
   echo "${CONFIG} missing - is rpi-image-gen installed?" >&2
   exit 1
}

# Separate an unusable environment from a broken package.
if ! unshare --user --map-root-user true 2>/dev/null ; then
   echo "SKIP: unprivileged user namespaces unavailable" >&2
   exit $SKIP
fi
if [ "$(dpkg --print-architecture)" != arm64 ] \
      && ! arch-test arm64 > /dev/null 2>&1 ; then
   echo "SKIP: arm64 binaries cannot be executed here; register aarch64" >&2
   echo "      with binfmt_misc to run this test on a non-arm64 host." >&2
   exit $SKIP
fi
if ! curl -fsS --max-time 60 -o /dev/null "https://deb.debian.org/debian/" ; then
   echo "SKIP: deb.debian.org unreachable" >&2
   exit $SKIP
fi

# mmdebstrap runs apt, which drops to the unprivileged _apt user to fetch.
# Every ancestor of the work directory has to be traversable by _apt, or apt
# reports the key directory as "not a directory" and the build fails with no
# hint as to why. AUTOPKGTEST_TMP, and anything from mktemp -d, is 0700.
chmod a+rx "$TMP" || exit 1
# Only check the ancestors - do not chmod them. Running as root we would
# "own" / and /tmp, and quietly relaxing those is not this test's business.
untraversable=
d=$(dirname "$TMP")
while : ; do
   case $(stat -c %a "$d") in
      *[!157]) untraversable="$d" ;;
   esac
   [ "$d" = / ] && break
   d=$(dirname "$d")
done
if [ -n "$untraversable" ] ; then
   echo "SKIP: ${untraversable} is not traversable by the _apt user, which" >&2
   echo "      apt drops to when fetching. chmod a+rx it and rerun." >&2
   exit $SKIP
fi

echo "== building ${CONFIG##*/}"
log=${TMP}/build.log
if ! ( cd "$TMP" && rpi-image-gen build -c "$CONFIG" ) > "$log" 2>&1 ; then
   echo "   FAILED - last 40 lines:"
   tail -40 "$log" | sed 's/^/   | /'
   exit 1
fi
echo "   ok"

# genimage names it system.erofs (genimage.cfg.in.erofs). Find it rather than
# assume the work directory layout, which is derived from the image name.
echo "== the system filesystem is erofs with a 16K block size"
shopt -s nullglob globstar
found=( "${TMP}"/**/system.erofs )
if (( ${#found[@]} == 0 )) ; then
   echo "   FAIL: no system.erofs produced"
   grep -i 'erofs' "$log" | tail -20 | sed 's/^/   | /'
   exit 1
fi

# erofs_super_block sits at offset 1024: magic at +0, blkszbits at +12. The
# block size has to be read back out of the image rather than taken from the
# command line, because accepting -b 16384 and writing it are different
# claims - and the second is the one a 2712 device depends on.
#
# Read the magic a byte at a time. erofs stores it little-endian, and od's
# multi-byte formats interpret in host order, so -tx4 would compare equal
# only on a little-endian builder. This package is Architecture: any.
fail=0
for img in "${found[@]}" ; do
   magic=$(od -An -tx1 -j1024 -N4 "$img" 2>/dev/null | tr -d ' \n')
   bits=$(od -An -tu1 -j1036 -N1 "$img" 2>/dev/null | tr -d ' ')
   if [[ $magic == e2e1f5e0 && $bits == 14 ]] ; then
      echo "   ok (${img#"$TMP"/}: blkszbits=$bits -> $((1 << bits)) bytes)"
   else
      echo "   FAIL: ${img#"$TMP"/} has magic bytes ${magic:-none}," \
           "blkszbits=${bits:-none}; wanted e2e1f5e0 and 14"
      fail=1
   fi
done

exit $fail
