#!/bin/sh
# SPDX-License-Identifier: GPL-3.0+
# Copyright 2020-2023 Lukas F. Hartmann <lukas@mntre.com>
# Copyright 2022-2025 Johannes Schauer Marin Rodrigues <josch@mister-muffin.de>
#
# The bootloader on either emmc or the sd-card (as decided by the position of the DIP
# switch) will load the kernel and initramfs from the first /boot partiton
# where it finds a valid boot.scr (or extlinux.conf). It will attempt to find
# a boot.scr on the first partition of the sd-card first and then will try
# the first partition on emmc.
#
# This script sets up the first partition on the sd-card or emmc (as decided
# by whether the --emmc option was passed or not) such that the initramfs on
# that partition will load the correct rootfs. The rootfs can either reside on
# the sd-card, emmc, ssd/nvme, sata or a usb mass storage device.
#
# The initramfs is tightly tied to the rootfs and the kernel version because it
# is generated from the contents of the rootfs and contains the kernel modules
# that must fit the correct kernel version. The choice of rootfs stored inside
# the initramfs is derived from the settings of /etc/fstab in the rootfs.

set -eu

usage() {
  echo "Usage: " >&2
  echo "  reform-boot-config [--emmc] sd    # rootfs on SD card (default)" >&2
  echo "  reform-boot-config [--emmc] ssd   # rootfs on SSD or NVMe" >&2
  echo "  reform-boot-config [--emmc] usb   # rootfs on USB storage device" >&2
  echo "  reform-boot-config [--emmc] emmc  # rootfs on eMMC" >&2
  echo "  reform-boot-config [--emmc] /dev/...  # custom rootfs device" >&2
  echo "" >&2
  echo "Adjust /etc/fstab of the given root file system and regenerate the" >&2
  echo "initramfs in /boot on eMMC or SD-card (as indicated by the --emmc" >&2
  echo "switch) to boot that rootfs." >&2
  echo "" >&2
  echo "Options:" >&2
  echo "      --emmc Record boot preference in /boot partition on eMMC instead of SD-card." >&2
  echo "      --no-copy-old-boot Do not copy contents from old /boot partition to new /boot." >&2
  echo "" >&2
  echo "Instead of using the short-hands sd, ssd, usb or emmc," >&2
  echo "you can choose another root partition by passing" >&2
  echo "the absolute device path starting with /dev/ explicitly." >&2
  echo "For example, to boot a rootfs on an LVM volume with /boot" >&2
  echo "on eMMC, run:" >&2
  echo "" >&2
  echo "    reform-boot-config --emmc /dev/reformvg/root" >&2
  echo "" >&2
  echo "Note: The Debian kernel package installs files into /boot. Thus, the" >&2
  echo "selected partition for /boot must already contain the kernel image" >&2
  echo "belonging to the Debian kernel package installed in the selected" >&2
  echo "rootfs. This script will not attempt to re-install the Debian kernel" >&2
  echo "package to re-populate an empty or non-matching /boot partition." >&2
  echo "" >&2
  echo "To re-create a /boot partition on eMMC from scratch, use" >&2
  echo "reform-emmc-bootstrap." >&2
  echo "" >&2
  echo "If 'ssd' was chosen as the root file system and there are no" >&2
  echo "partitions on the SSD, this script will attempt to open the SSD" >&2
  echo "as a LUKS device and assume a setup created by" >&2
  echo "reform-setup-encrypted-disk." >&2
}

maybe_umount() {
  what="$1"
  if [ "$FORCE" = true ]; then
    echo "Unmounting without user interaction because of --force"
    response="y"
  else
    printf "Should this script run 'umount %s' for you? [y/N] " "$what"
    read -r response
  fi
  if [ "$response" != "y" ]; then
    echo "I: Not unmounting as requested." >&2
    return 1
  else
    echo "I: Unmounting $what..."
    ret=0
    umount "$what" || ret=$?
    if [ "$ret" -eq 0 ]; then
      echo "I: Unmounting $what successful." >&2
      return 0
    else
      echo "E: Tried to unmount $what but failed." >&2
      return 1
    fi
  fi
}

FORCE=false
EMMC=false
COPY_OLDBOOT=true
while getopts :h-: OPTCHAR; do
  case "$OPTCHAR" in
    h)
      usage
      exit 0
      ;;
    -)
      case "$OPTARG" in
        help)
          usage
          exit 0
          ;;
        force) FORCE=true ;;
        emmc) EMMC=true ;;
        no-copy-old-boot) COPY_OLDBOOT=false ;;
        *)
          echo "E: unrecognized option: --$OPTARG" >&2
          exit 1
          ;;
      esac
      ;;
    :)
      echo "E: missing argument for -$OPTARG" >&2
      exit 1
      ;;
    '?')
      echo "E: unrecognized option -$OPTARG" >&2
      exit 1
      ;;
    *)
      echo "E: error parsing options" >&2
      exit 1
      ;;
  esac
done
shift "$((OPTIND - 1))"

if [ "$#" -ne 1 ]; then
  echo "E: invalid number of arguments" >&2
  usage
  exit 1
fi

ARGV1="$1"

if [ "$(id -u)" -ne 0 ]; then
  echo "reform-boot-config has to be run as root / using sudo." >&2
  exit 1
fi

# shellcheck source=/dev/null
if [ -e "./machines/$(cat /proc/device-tree/model).conf" ]; then
  . "./machines/$(cat /proc/device-tree/model).conf"
elif [ -e "/usr/share/reform-tools/machines/$(cat /proc/device-tree/model).conf" ]; then
  . "/usr/share/reform-tools/machines/$(cat /proc/device-tree/model).conf"
else
  echo "E: unable to find config for $(cat /proc/device-tree/model)" >&2
  exit 1
fi

if [ "$EMMC" = true ]; then
  case $EMMC_USE in
    false)
      echo "E: writing to eMMC not supported on $(cat /proc/device-tree/model)" >&2
      exit 1
      ;;
    warn)
      echo "W: Using eMMC on $(cat /proc/device-tree/model) is not without risk." >&2
      echo "W: For example, flashing the wrong bootloader or if the flashing process goes wrong, it is" >&2
      echo "W: possible to soft-brick your board. Restoring it might need some extra hardware." >&2
      echo "W: Please only proceed if you are sure that the benefits outweigh the risks for you." >&2
      if [ "$FORCE" = true ]; then
        echo "Proceeding without user interaction because of --force" >&2
        response="y"
      else
        printf "Are you sure you want to proceed? [y/N] "
        read -r response
      fi

      if [ "$response" != "y" ]; then
        echo "Exiting."
        exit
      fi
      ;;
  esac
  BOOTPART="$DEV_MMC"
  HUMAN_BOOT="eMMC"
else
  BOOTPART="$DEV_SD"
  HUMAN_BOOT="SD-card"
fi

# Try opening with an exclusive write lock to check whether a device is still
# opened by consumers like device-mapper, raid or luks, to name some examples.
# reform-emmc-bootstrap does the same thing (could share code?)
get_exclusive_write_lock() {
  ret=0
  python3 - "$1" <<EOF || ret=$?
import errno, os, sys

try:
    os.open(sys.argv[1], os.O_WRONLY | os.O_EXCL)
except OSError as e:
    if e.errno == errno.EBUSY:
        sys.exit(1)
    raise
EOF
  return $ret
}

echo "I: Using partition on $HUMAN_BOOT for /boot: /dev/${BOOTPART}p1."
if [ ! -e "/dev/${BOOTPART}p1" ]; then
  echo "W: Partition 1 on $HUMAN_BOOT does not exist" >&2
  echo "W: This script can create a new partition table on $HUMAN_BOOT for you." >&2
  echo "WARNING: doing so will destroy the contents of your $HUMAN_BOOT." >&2
  if [ "$FORCE" = true ]; then
    echo "I: Proceeding without user interaction because of --force" >&2
    response="y"
  else
    printf "Are you sure you want to proceed? [y/N] "
    read -r response
  fi

  if [ "$response" != "y" ]; then
    echo "Exiting."
    exit
  fi

  if ! get_exclusive_write_lock "/dev/${BOOTPART}"; then
    echo "E: device /dev/${BOOTPART} ($HUMAN_BOOT) is still in use" >&2
    exit 1
  fi

  # reform-emmc-bootstrap does the same thing (could share code?)
  parted --script --machine "/dev/$BOOTPART" "mklabel msdos"
  # create two partitions as expected by reform-check (but we only format /boot)
  # make /boot as big as mkimage.sh would
  parted --script --machine "/dev/$BOOTPART" "mkpart primary ext4 16MiB $((16 + 488))MiB"
  parted --script --machine "/dev/$BOOTPART" "mkpart primary ext4 $((16 + 488))MiB 100%"
  udevadm settle
  partprobe "/dev/$BOOTPART"
  mkfs.ext4 -F "/dev/${BOOTPART}p1"
fi
BOOTPART="${BOOTPART}p1"

if [ ! -b "/dev/$BOOTPART" ]; then
  echo "/dev/$BOOTPART is not a block device" >&2
  exit 1
fi

case $ARGV1 in
  sd) ROOTPART="${DEV_SD}p2" ;;
  nvme | ssd)
    if [ "$DEV_SSD" = "sda" ]; then
      ROOTPART="${DEV_SSD}1"
    else
      ROOTPART="${DEV_SSD}p1"
    fi
    if [ ! -e "/dev/$ROOTPART" ]; then
      echo "W: First partition on SSD (/dev/$ROOTPART) does not exist." >&2
      if cryptsetup isLuks "/dev/${DEV_SSD}"; then
        echo "I: Assuming full disk encryption with LUKS on /dev/reformvg/root" >&2
        ROOTPART="reformvg/root"
      else
        echo "E: Your SSD at /dev/${DEV_SSD} does not seem to be a LUKS device" >&2
        exit 1
      fi
    fi
    ;;
  usb) ROOTPART="${DEV_USB}1" ;;
  emmc) ROOTPART="${DEV_MMC}p2" ;;
  /dev/*)
    if [ ! -b "$1" ]; then
      echo "there is no block device called $1" >&2
      exit 1
    fi
    ROOTPART="$1"
    ;;
  *)
    usage
    exit 1
    ;;
esac

echo "This script selects your preferred boot medium. It writes your choice to the file /etc/fstab"
echo

ROOTPART="${ROOTPART#/dev/}"

# POSIX shell only has a single array: $@
# Instead of storing the list of directories that need to be unmounted or
# removed in a string separated by whitespaces (and thus not supporting
# whitespace characters in path names) we use $@ to store that list.
# We push each new entry to the beginning of the list so that we can use
# shift to pop the first entry.
cleanup() {
  : "${TMPDIR:=/tmp}"
  for dir; do
    # $dir is either a device that has to be unmounted or an empty
    # temporary directory that used to be a mountpoint
    echo "cleaning up $dir" >&2
    ret=0
    if [ -d "$dir" ]; then
      # special handling for /dev, /sys and /proc
      case "$dir" in
        */dev | */sys | */proc) umount "$dir" || ret=$? ;;
        *) rmdir "$dir" || ret=$? ;;
      esac
    else
      umount "$dir" || ret=$?
    fi
    if [ "$ret" != 0 ]; then
      echo "cleaning up $dir failed" >&2
    fi
    # remove this item from $@
    shift
  done
  if [ "${MOUNTROOT-}" = "/" ]; then
    ret=0
    mount /boot || ret=$?
    if [ "$ret" != 0 ]; then
      echo "mounting /boot failed" >&2
    fi
  fi
  if [ "${MOUNTROOT-}" != "/" ] && [ "$ROOTPART" = "reformvg/root" ] && [ "$ARGV1" != "/dev/reformvg/root" ]; then
    if [ -e /dev/reformvg ]; then
      vgchange -an reformvg >&2
    fi
    if [ -e /dev/mapper/reform_crypt ]; then
      cryptsetup luksClose reform_crypt
    fi
  fi
  echo reform-boot-config FAILED to run >&2
}
set --
trap 'cleanup "$@"' EXIT INT TERM

# check if rootfs is already mounted somewhere that is not /
if [ -b "/dev/$ROOTPART" ]; then
  MOUNTROOT="$(lsblk --noheadings --output=MOUNTPOINT "/dev/$ROOTPART" || :)"
  if [ "$MOUNTROOT" != "" ] && [ "$MOUNTROOT" != "/" ]; then
    echo "/dev/$ROOTPART is still mounted on $MOUNTROOT." >&2
    if ! maybe_umount "/dev/$ROOTPART"; then
      echo "Please unmount before running this script" >&2
      exit 1
    fi
    MOUNTROOT=
  fi
else
  # if /dev/$ROOTPART is not a block device, then it can also not be mounted anywhere
  MOUNTROOT=
fi

# If reformvg/root was chosen as the rootfs (either explicitly or implicitly
# because there are no partitions on the SSD), attempt opening the SSD as a
# LUKS device, except if either
#  - it is already mounted as the current rootfs or
#  - the user explicitly selected /dev/reformvg/root as the rootfs in which
#    case we assume it is already unlocked by the user
if [ "$MOUNTROOT" != "/" ] && [ "$ROOTPART" = "reformvg/root" ] && [ "$ARGV1" != "/dev/reformvg/root" ]; then
  if ! cryptsetup isLuks "/dev/${DEV_SSD}"; then
    echo "W: SSD (/dev/${DEV_SSD}) does not look like a LUKS device" >&2
  fi
  cryptsetup luksOpen "/dev/${DEV_SSD}" reform_crypt
  vgchange -ay reformvg >&2
fi

# mount the desired root partition somewhere if it isn't mounted yet
if [ "$MOUNTROOT" = "" ]; then
  if [ ! -e "/dev/$ROOTPART" ]; then
    echo "E: root partition (/dev/$ROOTPART) does not exist" >&2
    exit 1
  fi
  MOUNTROOT="$(mktemp --tmpdir --directory reform-boot-config.XXXXXXXXXX)"
  set -- "/dev/$ROOTPART" "$MOUNTROOT" "$@"
  mount "/dev/$ROOTPART" "$MOUNTROOT"
fi

if [ ! -d "$MOUNTROOT/boot" ]; then
  echo "the rootfs does not contain a /boot directory" >&2
  exit 1
fi

# check if the new boot is still mounted somewhere
MOUNT_BOOT="$(lsblk --noheadings --output=MOUNTPOINT "/dev/$BOOTPART" || :)"
if [ -n "$MOUNT_BOOT" ]; then
  echo "W: /dev/$BOOTPART ($HUMAN_BOOT) is still mounted on $MOUNT_BOOT, which means that it is" >&2
  echo "probably used by the currently running system and that replacing" >&2
  echo "its contents might make the currently running system unbootable."

  if [ "$(lsblk --noheadings --output=MOUNTPOINT "/dev/$BOOTPART")" != "/boot" ]; then
    echo "W: /dev/$BOOTPART ($HUMAN_BOOT) was expected to be mounted at /boot, but was found be" >&2
    echo "W: mounted at $(lsblk --noheadings --output=MOUNTPOINT "/dev/$BOOTPART")" >&2
  fi

  if ! maybe_umount "/dev/$BOOTPART"; then
    echo "Please unmount before running this script" >&2
    exit 1
  fi
fi

# check that the new mountpoint for /boot is empty
if mountpoint --quiet "$MOUNTROOT/boot"; then
  echo "Something ($(findmnt --noheadings --evaluate --mountpoint "$MOUNTROOT/boot" --output SOURCE)) is still mounted on $MOUNTROOT/boot." >&2
  if ! maybe_umount "$MOUNTROOT/boot"; then
    echo "Please unmount before running this script" >&2
    exit 1
  fi
fi

# mount the new boot partition
set -- "/dev/$BOOTPART" "$@"
mount "/dev/$BOOTPART" "$MOUNTROOT/boot"

# find the device that was mounted as /boot according to the /etc/fstab in the
# given rootfs
OLDBOOTPART="$(LIBMOUNT_FSTAB="$MOUNTROOT/etc/fstab" findmnt --fstab --noheadings --evaluate --mountpoint /boot --output SOURCE || :)"

if [ "$COPY_OLDBOOT" = true ]; then
  if [ -z "$OLDBOOTPART" ]; then
    echo "cannot find /boot device referenced by /etc/fstab in rootfs at /dev/$ROOTPART" >&2
    exit 1
  fi
  if [ ! -e "$OLDBOOTPART" ]; then
    echo "/boot device $OLDBOOTPART from /etc/fstab in /dev/$ROOTPART doesn't exist" >&2
    exit 1
  fi
  case $OLDBOOTPART in
    "/dev/${DEV_SD}"*) HUMAN_OLDBOOT="SD-card" ;;
    "/dev/${DEV_MMC}"*) HUMAN_OLDBOOT="eMMC" ;;
    *) HUMAN_OLDBOOT="unknown" ;;
  esac

  if [ "$OLDBOOTPART" = "/dev/$BOOTPART" ]; then
    echo "the /boot partition /dev/$BOOTPART ($HUMAN_BOOT) referenced by the rootfs at /dev/$ROOTPART remains the same" >&2
  else
    echo "This script will copy the contents from the old /boot partition" >&2
    echo "$OLDBOOTPART ($HUMAN_OLDBOOT) to the new /boot partition $BOOTPART ($HUMAN_BOOT) and delete all" >&2
    echo "files from the latter that were not present in the former." >&2
    if [ "$FORCE" = true ]; then
      echo "Proceeding without user interaction because of --force" >&2
      response="y"
    else
      echo "Are you sure that you want to remove the contents of $BOOTPART ($HUMAN_BOOT)" >&2
      printf "and replace it with the contents of %s? [y/N] " "$OLDBOOTPART ($HUMAN_OLDBOOT)" >&2
      read -r response
    fi
    if [ "$response" != "y" ]; then
      echo "I: Not overwriting the contents of $BOOTPART ($HUMAN_BOOT) as requested." >&2
      exit 1
    fi

    # copy the contents of the old /boot to the new /boot
    OLDMOUNTBOOT="$(lsblk --nodeps --noheadings --output=MOUNTPOINT "$OLDBOOTPART")"
    needumount="no"
    if [ "$OLDMOUNTBOOT" = "" ]; then
      OLDMOUNTBOOT="$(mktemp --tmpdir --directory reform-boot-config.XXXXXXXXXX)"
      set -- "$OLDBOOTPART" "$OLDMOUNTBOOT" "$@"
      mount "$OLDBOOTPART" "$OLDMOUNTBOOT"
      needumount="yes"
    fi

    # sanity check
    if ! mountpoint --quiet "$OLDMOUNTBOOT"; then
      echo "E: expected $OLDBOOTPART ($HUMAN_OLDBOOT) mounted on $OLDMOUNTBOOT but nothing mounted there" >&2
      exit 1
    fi

    rsync --archive --one-file-system --hard-links --acls --xattrs --whole-file \
      --sparse --numeric-ids --delete-delay "$OLDMOUNTBOOT/" "$MOUNTROOT/boot"
    if [ "$needumount" = "yes" ]; then
      [ "$1" = "$OLDBOOTPART" ] && shift && umount "$OLDBOOTPART"
      [ "$1" = "$OLDMOUNTBOOT" ] && shift && rmdir "$OLDMOUNTBOOT"
    fi
  fi
fi

if LIBMOUNT_FSTAB="$MOUNTROOT/etc/fstab" findmnt --fstab --noheadings --source "/dev/$ROOTPART" --mountpoint "/" >/dev/null \
  && LIBMOUNT_FSTAB="$MOUNTROOT/etc/fstab" findmnt --fstab --noheadings --source "/dev/$BOOTPART" --mountpoint "/boot" >/dev/null; then
  echo "/etc/fstab already contains the correct entries" >&2
else
  echo "commenting original /etc/fstab contents" >&2

  SWAP=
  if LIBMOUNT_FSTAB="$MOUNTROOT/etc/fstab" findmnt --fstab --types swap >/dev/null; then
    SWAP="$(LIBMOUNT_FSTAB="$MOUNTROOT/etc/fstab" findmnt --noheadings --fstab --types swap --output SOURCE,TARGET,FSTYPE,OPTIONS,FREQ,PASSNO)"
  fi

  sed -i -e 's/^/#/' "$MOUNTROOT/etc/fstab"
  cat <<END >>"$MOUNTROOT/etc/fstab"
/dev/$ROOTPART / auto errors=remount-ro 0 1
/dev/$BOOTPART /boot auto errors=remount-ro 0 1
END

  if [ -n "$SWAP" ]; then
    echo "$SWAP" >>"$MOUNTROOT/etc/fstab"
  fi
fi

if [ "$MOUNTROOT" = "/" ]; then
  update-initramfs -u
else
  set -- "$MOUNTROOT/proc" "$MOUNTROOT/sys" "$MOUNTROOT/dev" "$@"
  mount -o bind /dev "$MOUNTROOT/dev"
  mount -t sysfs sys "$MOUNTROOT/sys"
  mount -t proc proc "$MOUNTROOT/proc"
  # We do not run update-initramfs with -u as that will attempt to update an
  # existing initramfs and /boot may already contain an initramfs for a kernel
  # version that we do not have.
  # FIXME: this will fail if /boot contains a kernel that is newer than the
  # latest kernel the system has installed, see #1092765
  chroot "$MOUNTROOT" update-initramfs -c -k all
  [ "$1" = "$MOUNTROOT/proc" ] && shift && umount "$MOUNTROOT/proc"
  [ "$1" = "$MOUNTROOT/sys" ] && shift && umount "$MOUNTROOT/sys"
  [ "$1" = "$MOUNTROOT/dev" ] && shift && umount "$MOUNTROOT/dev"
fi

# unmount /boot partition
[ "$1" = "/dev/$BOOTPART" ] && shift && umount "/dev/$BOOTPART"

# unmount the root partition if necessary
if [ "$MOUNTROOT" != "/" ]; then
  [ "$1" = "/dev/$ROOTPART" ] && shift && umount "/dev/$ROOTPART"
  [ "$1" = "$MOUNTROOT" ] && shift && rmdir "$MOUNTROOT"
fi

# make sure that the cleanup array is empty now
[ $# -eq 0 ]

trap - EXIT INT TERM

if [ "$MOUNTROOT" != "/" ] && [ "$ROOTPART" = "reformvg/root" ] && [ "$ARGV1" != "/dev/reformvg/root" ]; then
  vgchange -an reformvg >&2
  cryptsetup luksClose reform_crypt
fi

# make sure that the new boot partition does not still have the reformsdboot
# or reformemmcboot labels in case it used to be the /boot partition from a
# rescue system on sd-card or emmc, respectively
case "$BOOTPART" in
  "${DEV_SD}p1")
    if [ "$(lsblk --nodeps --noheadings --properties-by=blkid --output=LABEL "/dev/$BOOTPART")" = "reformsdboot" ]; then
      e2label "/dev/$BOOTPART" ""
    fi
    ;;
  "${DEV_MMC}p1")
    if [ "$(lsblk --nodeps --noheadings --properties-by=blkid --output=LABEL "/dev/$BOOTPART")" = "reformemmcboot" ]; then
      e2label "/dev/$BOOTPART" ""
    fi
    ;;
esac

# since /boot had to be unmounted before running this script, make sure to
# mount it again
if [ "$MOUNTROOT" = "/" ]; then
  mount /boot
fi

# Maybe the human platform name should be part of the machine/*.conf if it is
# used more than just here.
case "$(cat /proc/device-tree/model)" in
  "MNT Pocket Reform with "*) PLATFORM_HUMAN="MNT Pocket Reform" ;;
  "MNT Reform Next with "*) PLATFORM_HUMAN="MNT Reform Next" ;;
  "MNT Reform 2" | "MNT Reform 2 HDMI") PLATFORM_HUMAN="Reform 2" ;;
  "MNT Reform 2 with "*) PLATFORM_HUMAN="MNT Reform" ;;
  "MNT "*) PLATFORM_HUMAN="MNT Reform (unknown)" ;;
esac

if [ "$EMMC" = true ]; then
  echo "Your /boot partition is on emmc (/dev/$BOOTPART)." >&2
  # If the current system runs on SD-card and the user set up /boot on eMMC
  # then they need to remove the SD-card before booting again or otherwise
  # u-boot will prefer /boot from this system.
  case $OLDBOOTPART in
    "/dev/${DEV_SD}"*)
      # If the user booted from sd-card before and is now told to remove the
      # SD-card for booting, it is possible that emmc does not contain u-boot
      # and in that case, the system will not boot anymore.
      #  * is there enough space in front of the first partition for u-boot?
      #  * if not, then there cannot be u-boot on emmc
      #  * if yes, check if it's the expected u-boot version
      # The above check is only sensible on platforms which store u-boot
      # directly on the main device and not in a /boot0 partition.
      if [ "$DEV_MMC_BOOT0" = false ] \
        && [ "$(parted --json --script "/dev/$DEV_MMC" unit B print 2>/dev/null | jq --raw-output '.disk.label')" != "unknown" ] \
        && [ "$(parted --json --script "/dev/$DEV_MMC" unit B print | jq --raw-output '.disk.partitions | length')" -ne 0 ] \
        && [ "$(parted --json --script "/dev/$DEV_MMC" unit B print | jq --raw-output '.disk.partitions[0].start' | sed 's/B$//')" -lt "16777216" ]; then
        echo "E: The first partition on your eMMC (/dev/$DEV_MMC) starts before 16 MiB" >&2
        echo "E: This is usually not sufficient space for the bootloader (for example on RK3588)" >&2
        echo "E: If you do not have the bootloader on eMMC, then removal of your SD-card will" >&2
        echo "E: likely make your system unbootable but leaving your SD-card plugged in" >&2
        echo "E: will make your bootloader prefer booting the system on SD-card. Best prepare a" >&2
        echo "E: SD-card containing only the bootloader and no bootable system or flash the bootloader" >&2
        echo "E: to emmc using reform-flash-bootloader." >&2
        echo >&2
      fi
      if [ -e /boot/flash.bin ]; then
        bootloadersize=$(stat --format=%s "/boot/flash.bin")
        realdev="/dev/${DEV_MMC}"
        if [ "$DEV_MMC_BOOT0" = true ]; then
          realdev="/dev/${DEV_MMC}boot0"
        fi
        if cmp --quiet --bytes="$((bootloadersize - FLASHBIN_OFFSET))" "--ignore-initial=0:$BOOTLOADER_OFFSET" /dev/zero "$realdev" 2>/dev/null; then
          echo "E: The space where the bootloader would've been on eMMC is all zeroes." >&2
          echo "E: Removal of your SD-card will make your system unbootable but" >&2
          echo "E: leaving your SD-card plugged in will make your bootloader prefer booting" >&2
          echo "E: the system on SD-card. Best prepare a SD-card containing only" >&2
          echo "E: the bootloader and no bootable system or flash the bootloader to emmc using" >&2
          echo "E: reform-flash-bootloader" >&2
        fi
      fi
      echo "I: The bootloader will prefer the first partition on SD-card over the first partition on eMMC" >&2
      echo "I: Your current system has its /boot mounted from SD-card." >&2
      echo "I: You requested to configure a new /boot on eMMC" >&2
      echo "I: Instead of just rebooting, power off the system." >&2
      echo "I: Then remove the SD-card." >&2
      echo "I: Lastly, power the system on again." >&2
      echo "I: Power off your ${PLATFORM_HUMAN} by running 'systemctl poweroff'." >&2
      case "$(cat /proc/device-tree/model)" in "MNT Reform 2" | "MNT Reform 2 HDMI")
        echo "I: WARNING: If you have the DIP switch on your i.MX8MQ set to load u-boot" >&2
        echo "I:          from SD-card instead of eMMC, you cannot boot the system without" >&2
        echo "I:          an SD-card inserted. In that case, either:" >&2
        echo "I:            a) mv /boot/boot.scr /boot/boot.scr.bak" >&2
        echo "I:            b) or put in a different SD-card with u-boot but without /boot/boot.scr" >&2
        ;;
      esac
      ;;
    *)
      echo "I: Reboot your ${PLATFORM_HUMAN} by running 'systemctl reboot'." >&2
      ;;
  esac
else
  echo "Your /boot partition is on your SD-Card (/dev/$BOOTPART)." >&2
  echo "I: Reboot your ${PLATFORM_HUMAN} by running 'systemctl reboot'." >&2
fi
