#!/bin/sh
# SPDX-License-Identifier: GPL-3.0+
# Copyright 2022-2025 Johannes Schauer Marin Rodrigues <josch@mister-muffin.de>
#
# This script checks the integrity of your MNT reform setup. It is meant for
# two main use-cases:
#
#  1. somebody has a problem with their reform and to debug the problem it
#     would be useful to know how their system differs from the default
#  2. somebody installed their system several months ago and now wants to find
#     out which things have since been added or changed in the defaults that
#     they might want to apply to their running setup as well
#
# Running this script as non-root will give you a diff between the files in
# /etc/skel and those in your $HOME. Running this script as root performs the
# system-wide checks.
#
# shellcheck disable=SC2059,SC1091,SC2034

set -eu

SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)

COMMON_LIB=
for candidate in \
  "$SCRIPT_DIR/../reform-check/common.sh" \
  "/usr/share/reform-tools/common.sh"; do
  if [ -r "$candidate" ]; then
    COMMON_LIB="$candidate"
    break
  fi
done
if [ -z "$COMMON_LIB" ]; then
  echo "E: unable to locate reform-check/common.sh" >&2
  exit 1
fi
# shellcheck source=../reform-check/common.sh
. "$COMMON_LIB"

usage() {
  echo "This script checks the integrity of your MNT reform setup. It is meant for" >&2
  echo "two main use-cases:" >&2
  echo >&2
  echo " 1. somebody has a problem with their reform and to debug the problem it" >&2
  echo "    would be useful to know how their system differs from the default" >&2
  echo " 2. somebody installed their system several months ago and now wants to find" >&2
  echo "    out which things have since been added or changed in the defaults that" >&2
  echo "    they might want to apply to their running setup as well" >&2
  echo >&2
  echo "Running this script as non-root will give you a diff between the files in" >&2
  # shellcheck disable=SC2016
  echo '/etc/skel and those in your $HOME. Running this script as root performs the' >&2
  echo "system-wide checks." >&2
  echo >&2
  echo "Usage: $0 [--help] [--mirror={mntre.com,reform.debian.net,archlinuxarm.org}] [--offline]" >&2
  echo >&2
  echo "Options:" >&2
  echo "  --help           Display this help and exit." >&2
  echo "  --mirror=MIRROR  Force MIRROR, currently mntre.com, reform.debian.net" >&2
  echo "                   or archlinuxarm.org" >&2
  echo "  --offline        Disable all checks that require an internet connection" >&2
  echo "                   and a filled apt cache." >&2
}

nth_arg() {
  shift "$1"
  printf "%s" "$1"
}

OFFLINE=
# Read by distro.sh and backend scripts to select and validate the package
# mirror, which is set via --mirror option below.
MIRROR=

while getopts :h-: OPTCHAR; do
  case "$OPTCHAR" in
    h)
      usage
      exit 0
      ;;
    -)
      case "$OPTARG" in
        help)
          usage
          exit 0
          ;;
        offline) OFFLINE=yes ;;
        mirror)
          if [ "$OPTIND" -gt "$#" ]; then
            echo "E: missing argument for --mirror" >&2
            exit 1
          fi
          MIRROR="$(nth_arg "$OPTIND" "$@")"
          OPTIND=$((OPTIND + 1))
          ;;
        mirror=*)
          MIRROR="${OPTARG#*=}"
          ;;
        *)
          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 [ "$#" -gt 0 ]; then
  usage
  exit 1
fi

DISTRO_LIB=
for candidate in \
  "$SCRIPT_DIR/../reform-check/distro.sh" \
  "/usr/share/reform-tools/distro.sh"; do
  if [ -r "$candidate" ]; then
    DISTRO_LIB="$candidate"
    break
  fi
done
if [ -z "$DISTRO_LIB" ]; then
  echo "E: distro backend loader is missing or unreadable" >&2
  exit 1
fi
# Read by distro.sh to construct the path to the distro-specific backend file.
DISTRO_LIB_DIR=$(CDPATH='' cd -- "$(dirname -- "$DISTRO_LIB")" && pwd)
# shellcheck source=../reform-check/distro.sh
. "$DISTRO_LIB"

PKG_KERNEL_MAIN="$(backend_kernel_pkg_name || true)"
PKG_KERNEL_HEADERS="$(backend_kernel_headers_pkg_name || true)"
PKG_REFORM_TOOLS="$(backend_tools_pkg_name || true)"
PKG_FWUPD="$(backend_fwupd_pkg_name || true)"
PKG_JQ="$(backend_jq_pkg_name || true)"
PKG_REFORM_MCU_TOOL="$(backend_mcu_tool_pkg_name || true)"

if ! backend_validate_options; then
  echo "E: validating distro backend options failed" >&2
  exit 1
fi

if [ "$(id -u)" -ne 0 ]; then
  # check several versions of ~/.profile that older versions of reform-system-image placed into /etc/skel
  # shellcheck disable=SC2016
  if grep --silent -F 'if [ $(whoami) == "root" ]; then cat /etc/reform-root-help; elif [ -z $WAYLAND_DISPLAY ]; then cat /etc/reform-help; fi' ~/.profile \
    || grep --silent -F 'if [ $(whoami) = "root" ]; then cat /etc/reform-root-help; elif [ -z $WAYLAND_DISPLAY ]; then cat /etc/reform-help; fi' ~/.profile \
    || grep --silent -F 'if [ "$(whoami)" = "root" ]; then cat /etc/reform-root-help; elif [ -z "$WAYLAND_DISPLAY" ]; then cat /etc/reform-help; fi' ~/.profile; then
    echo "E: Your ~/.profile contains an outdated line that attempts to print /etc/reform-root-help or /etc/reform-help." >&2
    echo "E: Consider replacing it with this version:" >&2
    echo 'if [ "$(whoami)" = "root" ]; then reform-help --root; elif [ -z "$WAYLAND_DISPLAY" ]; then reform-help; fi' >&2
  fi

  if [ -e /usr/share/glib-2.0/schemas/20_reform.gschema.override ]; then
    if ! python3 - /usr/share/glib-2.0/schemas/20_reform.gschema.override <<'END'; then
import gi
from gi.repository import GLib, Gio
import sys

kf = GLib.KeyFile.new()
kf.load_from_file(sys.argv[1], GLib.KeyFileFlags.NONE)
source = Gio.SettingsSchemaSource.get_default()

suggestions = []
for group in kf.get_groups()[0]:
    if not source.lookup(group, False):
        print(f"N: schema {group} does not exist")
        continue
    settings = Gio.Settings(schema_id=group)
    for key in kf.get_keys(group)[0]:
        if not settings.get_property("settings_schema").has_key(key):
            print(f"N: {group} has no setting called {key}")
            continue
        if settings.get_user_value(key):
            print(f"I: {group} {key} was changed")
            print(f"I:    default value: {kf.get_value(group, key)}")
            print(f"I:    current value: {settings.get_user_value(key)}")
            suggestions.append(f"gsettings reset {group} {key}")
if not suggestions:
    exit(1)
print("I: the following commands return the respective settings to their defaults")
print("    " + "\n    ".join(suggestions))
END
      echo "I: unable to run gsettings defaults check, skipping." >&2
    fi
  else
    echo "I: /usr/share/glib-2.0/schemas/20_reform.gschema.override does not exist, skipping gsettings defaults check." >&2
  fi

  for path in $(cd /etc/skel && find . -type f); do
    if [ ! -e "$HOME/$path" ]; then
      echo "W: $path doesn't exist in current \$HOME" >&2
    elif ! cmp --quiet "/etc/skel/$path" "$HOME/$path"; then
      echo "W: local version of $path has modifications:" >&2
      diff -u "/etc/skel/$path" "$HOME/$path" || true
    fi
  done
  echo "I: Running reform-check as the normal user only diffs your current"
  # shellcheck disable=SC2016
  echo 'I: configuration in your $HOME against the contents in /etc/skel.'
  echo "I: To run a system-wide check, run this script as the root user."
  exit 0
fi

if ! backend_preflight_checks; then
  echo "E: running distro backend preflight checks failed" >&2
  exit 1
fi

if [ ! -e /proc/device-tree/model ]; then
  echo "E: /proc/device-tree/model does not exist" >&2
  exit 1
fi
MODEL="$(read_nul_terminated_file /proc/device-tree/model)"

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

echo "I: Contents of /proc/device-tree/model: $MODEL" >&2
echo "I: \`uname -a\` output: $(uname -a)" >&2
if [ -n "$PKG_KERNEL_MAIN" ] && backend_pkg_installed "$PKG_KERNEL_MAIN"; then
  echo "I: Version of $PKG_KERNEL_MAIN: $(backend_pkg_version "$PKG_KERNEL_MAIN")" >&2
else
  # The error message below is not quite correct. dpkg *will* tell us a version
  # even when a package was removed (but not purged). But showing a version
  # for a removed package is misleading the reader of the reform-check output
  # into believing that the package is actually installed (or why else would
  # it show the version of the package?). Thus, when the package is not
  # installed, we forcefully do not show the version even though we could.
  echo "E: Cannot get version of ${PKG_KERNEL_MAIN:-main kernel package} as it is not installed" >&2
fi
if backend_pkg_installed "$PKG_REFORM_TOOLS"; then
  echo "I: Version of $PKG_REFORM_TOOLS: $(backend_pkg_version "$PKG_REFORM_TOOLS")" >&2
else
  echo "E: $PKG_REFORM_TOOLS is not installed" >&2
fi

if grep --quiet "System Image " /etc/motd; then
  echo "I: Version of system image: $(grep --only-matching "System Image .*" /etc/motd)" >&2
else
  echo "W: Unable to infer version of system image from /etc/motd" >&2
fi

case "$MODEL" in
  "MNT Pocket Reform with "*" Module")
    if [ "$OFFLINE" != "yes" ] && [ ! -e /var/cache/fwupd/metadata.xmlb ] && command -v fwupdtool >/dev/null; then
      echo "I: running fwupdtool refresh" >&2
      ret=0
      fwupdtool refresh || ret=$?
      if [ "$ret" != 0 ]; then
        echo "E: fwupdtool refresh failed -- you can skip checking for the latest firmware version with --offline" >&2
        exit 1
      fi
    fi
    LATEST_SYS_VER=""
    # fwupdmgr search was added in fwupd 2.0.16 (commit b2d8491); older
    # fwupd versions need to fall back to xb-tool against the cached metadata
    FWUPD_VERSION=""
    if have_cmd fwupdmgr; then
      FWUPD_VERSION="$(fwupdmgr --version 2>/dev/null | awk '/^runtime[[:space:]]+org\.freedesktop\.fwupd/ {print $3; exit}')"
    fi
    if [ "$OFFLINE" != "yes" ]; then
      if have_cmd jq && [ -n "$FWUPD_VERSION" ] && version_ge "$FWUPD_VERSION" "2.0.16"; then
        LATEST_SYS_VER="$(fwupdmgr search --json com.mntre.pocket_reform.sysctl10.firmware 2>/dev/null \
          | jq --raw-output '.Releases[0].Version // empty' 2>/dev/null || true)"
      elif command -v unxz >/dev/null && command -v curl >/dev/null && command -v xmllint >/dev/null; then
        LATEST_SYS_VER="$(curl --silent https://fwupd.org//downloads/firmware.xml.xz | unxz | xmllint --xpath "string(/components/component[id[text()='com.mntre.pocket_reform.sysctl10.firmware']]/releases/release[1]/@version)" - || true)"
      fi
    elif have_cmd xb-tool && [ -e /var/cache/fwupd/metadata.xmlb ]; then
      LATEST_SYS_VER="$(xb-tool query /var/cache/fwupd/metadata.xmlb "components/component/id[text()='com.mntre.pocket_reform.sysctl10.firmware']/../releases/release[1]" 2>/dev/null || true)"
    fi
    if [ -z "$LATEST_SYS_VER" ]; then
      echo "I: To retrieve the latest sysctl and keyboard firmware versions install ${PKG_FWUPD:-fwupd} (>= 2.0.16) and ${PKG_JQ:-jq}, install xb-tool, or install curl, xz-utils and libxml2-utils" >&2
      if [ "$OFFLINE" = "yes" ]; then
        echo "I: Checking for the latest firmware version requires reform-check to be run without --offline" >&2
      fi
    fi

    if have_cmd reform-mcu-tool && have_cmd jq; then
      MCU_LIST_JSON="$(reform-mcu-tool list --json 2>/dev/null || true)"
      SYS_VER="$(printf '%s' "$MCU_LIST_JSON" | jq --raw-output 'map(select(.device.name == "pocket-sysctl-1.0")) | .[] | .version' 2>/dev/null || true)"
      if [ -n "$SYS_VER" ]; then
        echo "I: Version of system controller firmware: $SYS_VER" >&2
        if [ -n "$LATEST_SYS_VER" ] && [ "$LATEST_SYS_VER" != "$SYS_VER" ]; then
          echo "I: Latest version of system controller firmware: $LATEST_SYS_VER" >&2
        fi
      else
        echo "W: unable to obtain version of system controller firmware -- firmware too old?" >&2
      fi
      KBD_VER="$(printf '%s' "$MCU_LIST_JSON" | jq --raw-output 'map(select(.device.name == "pocket-input-1.0")) | .[] | .version' 2>/dev/null || true)"
      if [ -n "$KBD_VER" ]; then
        echo "I: Version of keyboard firmware: $KBD_VER" >&2
      else
        echo "W: unable to obtain version of keyboard firmware -- firmware too old?" >&2
      fi
    else
      echo "I: Install ${PKG_REFORM_MCU_TOOL:-reform-tools} and ${PKG_JQ:-jq} to query Pocket controller and keyboard firmware versions" >&2
    fi
    ;;
esac

SPINUM=0
case "$MODEL" in
  "MNT Reform 2 with LS1028A Module" | \
    "MNT Reform 2 with BPI-CM4 Module" | \
    "MNT Pocket Reform with BPI-CM4 Module") : ;; # nothing to do, SPINUM stays zero
  "MNT Reform 2" | "MNT Reform 2 HDMI" | \
    "MNT Reform 2 with i.MX8MP Module" | \
    "MNT Reform 2 with QUASAR QCS8550 Module" | \
    "MNT Reform 2 with RCORE-DSI RK3588 Module" | \
    "MNT Reform 2 with RCORE RK3588 Module" | \
    "MNT Reform Next with RCORE RK3588 Module" | \
    "MNT Pocket Reform with i.MX8MP Module" | \
    "MNT Pocket Reform with RCORE RK3588 Module") SPINUM=1 ;;
  "MNT Pocket Reform with QUASAR QCS6490 Module" | \
    "MNT Reform 2 with QUASAR QCS6490 Module" | \
    "MNT Reform Next with QUASAR QCS6490 Module") SPINUM=4 ;;
esac
if [ -e "/sys/bus/spi/drivers/reform2_lpc/spi${SPINUM}.0/firmware" ]; then
  echo "I: Version of LPC firmware: $(cat /sys/bus/spi/drivers/reform2_lpc/spi${SPINUM}.0/firmware)"
else
  echo "W: /sys/bus/spi/drivers/reform2_lpc/spi1.0/firmware does not exist -- is the reform2_lpc module loaded?" >&2
fi

if [ -e "/proc/device-tree/chosen/u-boot,version" ]; then
  UBOOT_VERSION_RAW="$(read_nul_terminated_file /proc/device-tree/chosen/u-boot,version)"
  version="$(parse_uboot_version "$UBOOT_VERSION_RAW" "$MODEL")"
  if [ -z "$version" ]; then
    echo "I: Contents of /proc/device-tree/chosen/u-boot,version: $UBOOT_VERSION_RAW" >&2
    echo "W: Unable to parse contents of /proc/device-tree/chosen/u-boot,version -- U-Boot too old?" >&2
  else
    if [ "$version" != "$BOOTLOADER_TAG" ]; then
      echo "I: Contents of /proc/device-tree/chosen/u-boot,version: $UBOOT_VERSION_RAW" >&2
      echo "I: Booting with outdated U-Boot. Local version is $version while latest version is $BOOTLOADER_TAG" >&2
    fi
    echo "I: Version of MNT U-Boot: $version" >&2
  fi
else
  echo "W: /proc/device-tree/chosen/u-boot,version does not exist -- U-Boot version too old?" >&2
fi

if ! BOOT_METHOD="$(backend_boot_tool_checks)"; then
  echo "E: running distro backend boot tool checks failed" >&2
  exit 1
fi

ROOT_SOURCE="$(findmnt --noheadings --evaluate --mountpoint / --output SOURCE)"
BOOT_SOURCE="$(findmnt --noheadings --evaluate --mountpoint /boot --output SOURCE)"
ROOT_FSTAB_SOURCE="$(findmnt --fstab --noheadings --evaluate --mountpoint / --output SOURCE)"
BOOT_FSTAB_SOURCE="$(findmnt --fstab --noheadings --evaluate --mountpoint /boot --output SOURCE)"

HUMAN_ROOT=
case "$ROOT_SOURCE" in
  "/dev/reformvg/root")
    pv_device="$(pvdisplay --noheadings --select vgname=reformvg --columns --options pv_name || true)"
    pv_device="${pv_device#  }" # remove whitespace prefix
    if [ "$pv_device" = "/dev/mapper/reform_crypt" ]; then
      luks_disk="$(lsblk --json -o PATH,PKNAME | jq --raw-output '.blockdevices[] | select(.path == "/dev/mapper/reform_crypt") | .pkname' || true)"
      case "$luks_disk" in
        "${DEV_SSD}") HUMAN_ROOT="LVM vg 'reformvg' on LUKS device 'reform_crypt' on SSD" ;;
        "${DEV_MMC}"*) HUMAN_ROOT="LVM vg 'reformvg' on LUKS device 'reform_crypt' on eMMC" ;;
        *) echo "W: reform_crypt LUKS device on unusual disk: /dev/$luks_disk" >&2 ;;
      esac
    else
      echo "W: LVM volume group reformvg on unexpected partition: $pv_device" >&2
    fi
    ;;
  "/dev/${DEV_MMC}"*) HUMAN_ROOT="eMMC" ;;
  "/dev/${DEV_SD}"*) HUMAN_ROOT="SD-card" ;;
  "/dev/${DEV_SSD}"*) HUMAN_ROOT="SSD" ;;
esac
echo "I: Mount source of /: $ROOT_SOURCE (${HUMAN_ROOT:-n.a.})" >&2
HUMAN_BOOT=
case "$BOOT_SOURCE" in
  "/dev/${DEV_MMC}"*) HUMAN_BOOT="eMMC" ;;
  "/dev/${DEV_SD}"*) HUMAN_BOOT="SD-card" ;;
esac
echo "I: Mount source of /boot: $BOOT_SOURCE (${HUMAN_BOOT})" >&2

if ! backend_repo_checks; then
  echo "E: running distro backend repository checks failed" >&2
  exit 1
fi

if [ -z "$ROOT_FSTAB_SOURCE" ]; then
  echo "E: your /etc/fstab does not have an entry for /" >&2
  echo "E: your / device probably is: $ROOT_SOURCE" >&2
  echo "E: add this to your /etc/fstab:" >&2
  echo "$ROOT_SOURCE / auto errors=remount-ro 0 1" >&2
fi

if [ -z "$BOOT_FSTAB_SOURCE" ]; then
  echo "E: your /etc/fstab does not have an entry for /boot" >&2
  if [ "$EMMC_USE" = true ]; then
    echo "E: for eMMC booting, add:" >&2
    echo "/dev/${DEV_MMC}p1 /boot auto errors=remount-ro 0 1" >&2
  fi
  echo "E: for SD-Card booting, add:" >&2
  echo "/dev/${DEV_SD}p1 /boot auto errors=remount-ro 0 1" >&2
fi

if ! mountpoint --quiet /boot; then
  echo "E: your /boot has nothing mounted on it -- fix your /etc/fstab" >&2
fi

if [ "$EMMC_USE" = true ] && [ ! -e "/dev/${DEV_MMC}p2" ]; then
  echo "W: /dev/${DEV_MMC}p2 doesn't exist." >&2
  echo "W: To update your eMMC to Debian sysimage-v5 you can run reform-flash-rescue" >&2
  echo "W: Only run reform-flash-rescue if you intend a factory-reset of your eMMC" >&2
  echo "W: Do not use reform-flash-rescue if you boot from eMMC because this will overwrite your /boot partition" >&2
fi

if [ ! -e /etc/motd ]; then
  echo "I: /etc/motd does not exist" >&2
elif [ ! -L /etc/motd ]; then
  echo "I: /etc/motd does not exist" >&2
elif [ "$(readlink /etc/motd)" != "motd-rescue" ] && [ "$(readlink /etc/motd)" != "motd-full" ]; then
  echo "I: /etc/motd does neither point to motd-rescue nor to motd-full" >&2
fi

backend_skel_profile_checks

pkg_verify_output="$(backend_pkg_verify "$PKG_REFORM_TOOLS" 2>/dev/null || true)"
if [ -n "$pkg_verify_output" ]; then
  echo "I: the following files differ from how they are shipped by $PKG_REFORM_TOOLS (ignore /var/lib/alsa/asound.state):" >&2
  printf '%s\n' "$pkg_verify_output" >&2
fi

if [ -n "$PKG_KERNEL_MAIN" ] && ! backend_pkg_installed "$PKG_KERNEL_MAIN"; then
  echo "E: $PKG_KERNEL_MAIN is not installed" >&2
fi

if [ -n "$PKG_KERNEL_HEADERS" ] && ! backend_pkg_installed "$PKG_KERNEL_HEADERS"; then
  echo "E: $PKG_KERNEL_HEADERS is not installed (cannot compile reform2_lpc.ko DKMS module for battery status)" >&2
fi

backend_kernel_artifact_checks

if ! backend_running_kernel_pkg_installed; then
  echo "E: the currently running kernel is not installed as a package" >&2
fi
if [ -n "$PKG_KERNEL_MAIN" ] && backend_pkg_installed "$PKG_KERNEL_MAIN" \
  && ! backend_running_kernel_matches_main_pkg; then
  echo "E: the currently running kernel is not the one provided by $PKG_KERNEL_MAIN" >&2
fi

if [ -e "/etc/modprobe.d/reform.conf" ]; then
  if cmp --quiet "/usr/lib/modprobe.d/reform.conf" "/etc/modprobe.d/reform.conf"; then
    echo "W: Your /etc/modprobe.d/reform.conf is identical to /usr/lib/modprobe.d/reform.conf" >&2
    echo "W: The reform.conf in /etc overrides the file in /usr which is shipped by the reform-tools package." >&2
    echo "W: You can thus safely delete your /etc/modprobe.d/reform.conf in favour of the copy shipped by reform-tools in /usr." >&2
  else
    echo "W: your custom /etc/modprobe.d/reform.conf overrides /usr/lib/modprobe.d/reform.conf" >&2
  fi
fi

if [ -e /proc/modules ] && ! grep --quiet '^reform2_lpc ' /proc/modules; then
  echo "E: reform2_lpc is not loaded (battery status information will be missing)" >&2
fi

if ! backend_modules_check; then
  echo "E: running distro backend module checks failed" >&2
fi

if [ ! -e "/sys/class/power_supply/BAT0" ]; then
  echo "E: /sys/class/power_supply/BAT0 is missing -- reform2_lpc module not loaded?" >&2
elif [ ! -L "/sys/class/power_supply/BAT0" ]; then
  echo "E: /sys/class/power_supply/BAT0 exists but is not a symlink" >&2
else
  BAT0_LINK="$(readlink /sys/class/power_supply/BAT0)"
  case "$BAT0_LINK" in
    ../../devices/platform/*"/spi_master/spi${SPINUM}/spi${SPINUM}.0/power_supply/BAT0") : ;;
    *) echo "E: unexpected link target of /sys/class/power_supply/BAT0: $BAT0_LINK" >&2 ;;
  esac
fi

if [ "$(tr ' ' '\n' </proc/cmdline | sort -u)" != "$(echo "$BOOTARGS" | tr ' ' '\n' | sort -u)" ]; then
  if [ -n "$(worddiff "$(cat /proc/cmdline)" "$BOOTARGS")" ]; then
    echo "I: kernel boot parameters your system does use but which are not the default:" >&2
    worddiff "$(cat /proc/cmdline)" "$BOOTARGS" | sed 's/^/ + /' >&2
  fi
  if [ -n "$(worddiff "$BOOTARGS" "$(cat /proc/cmdline)")" ]; then
    echo "I: kernel boot parameters which are the default but your system doesn't use them:" >&2
    worddiff "$BOOTARGS" "$(cat /proc/cmdline)" | sed 's/^/ - /' >&2
  fi
fi

if [ "$(tr ' ' '\n' </proc/cmdline | grep console= | tail -1)" != "console=tty1" ]; then
  echo "W: The last console= parameter in your cmdline is not console=tty1." >&2
  echo "W: This could lead to the luks password prompt being printed to serial instead of your screen." >&2
fi

case "$(cat /proc/cmdline)" in *" single "* | "single "* | *" single" | "single")
  echo "W: Your kernel cmdline has 'single' in it and will boot into rescue mode on each boot. Maybe booting via extlinux.conf failed?" >&2
  ;;
esac

if [ -e "/boot/extlinux/extlinux.conf" ]; then
  if ! grep --quiet '^[	 ]\+\(fdt\|fdtdir\) ' /boot/extlinux/extlinux.conf; then
    echo "E: neither fdt nor fdtdir lines found in /boot/extlinux/extlinux.conf" >&2
  fi
fi

case "$MODEL" in
  "MNT Pocket Reform with RCORE RK3588 Module" | \
    "MNT Reform 2 with RCORE-DSI RK3588 Module" | \
    "MNT Reform 2 with RCORE RK3588 Module" | \
    "MNT Reform Next with RCORE RK3588 Module")
    features=$(awk -F": " '/^Features\t: / { print $2; }' /proc/cpuinfo | sort)
    # features aes, pmull, sha1 and sha2 were found to be missing with wrong TF-A version
    # https://mntre.com/reform-irc-logs/2025-10-25.log.html
    # https://tooting.ch/@vimja/115435628986765190
    for feature in fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm lrcpc dcpop asimddp; do
      case " $features " in
        *" $feature "*) : ;; # feature is part of features
        *) echo "E: /proc/cpuinfo does not list $feature as feature -- wrong TF-A version?" >&2 ;;
      esac
    done
    ;;
esac

if ! backend_running_kernel_headers_pkg_installed; then
  hdr_pkg="$(backend_running_kernel_headers_pkg_name 2>/dev/null || true)"
  echo "E: the header package${hdr_pkg:+ $hdr_pkg} for the currently running kernel is not installed (cannot compile reform2_lpc.ko DKMS module for battery status)" >&2
else
  # even if the package is installed, the directory might be missing for some reason
  if [ ! -d "/usr/lib/modules/$(uname -r)/build/include" ]; then
    echo "E: the kernel header files cannot be found at /usr/lib/modules/$(uname -r)/build/include even though the header package for the running kernel is installed" >&2
  fi
fi

if ! backend_distro_specific_checks; then
  echo "E: running distro backend distro-specific checks failed" >&2
fi

if ! backend_initramfs_checks "$BOOT_METHOD"; then
  echo "E: running distro backend initramfs checks failed" >&2
fi

if [ ! -e "/dev/dri/renderD128" ]; then
  echo "E: /dev/dri/renderD128 does not exist -- no hardware accelerated rendering" >&2
elif [ ! -c "/dev/dri/renderD128" ]; then
  echo "E: /dev/dri/renderD128 exists but is not a character-special device" >&2
else
  if [ "$(stat -c %G /dev/dri/renderD128)" != "render" ]; then
    echo "W: /dev/dri/renderD128 is not owned by the render group" >&2
  fi
  if ! udevadm info --query=property --property=TAGS --value /dev/dri/renderD128 | grep --fixed-strings --quiet ":uaccess:"; then
    echo "E: udev does not have /dev/dri/renderD128 tagged with 'uaccess' -- non-root user will not have access to hardware rendering" >&2
  fi
fi

if ! grep --quiet 'SUBSYSTEM=="drm",.*KERNEL=="renderD.*TAG+="uaccess"' /usr/lib/udev/rules.d/*; then
  echo "E: missing udev rule to add the 'uaccess' tag to /dev/dri/renderD128" >&2
fi

if [ -n "${SUDO_USER:-}" ]; then
  if id --name --groups --zero "$SUDO_USER" \
    | grep --quiet --null-data --line-regexp --fixed-strings render; then
    # SUBSYSTEM=="drm", KERNEL=="renderD*", TAG+="uaccess"
    echo "I: user $SUDO_USER is in the render group which should not be necessary" >&2
    echo "I: to gain access to /dev/dri/renderD128, use ACLs as they are set by udev's uaccess tag" >&2
  fi
  if [ -e "/dev/dri/renderD128" ]; then
    if ! getfacl --omit-header --absolute-names /dev/dri/renderD128 | grep --line-regexp --fixed-strings --quiet -- "user:$SUDO_USER:rw-"; then
      echo "E: ACL of /dev/dri/renderD128 does not contain an entry for $SUDO_USER -- missing access means no hardware rendering for non-root users" >&2
    fi
  fi
else
  echo "I: not executed with sudo -- cannot do tests for the user who ran sudo" >&2
fi

if test -s /sys/kernel/debug/devices_deferred; then
  echo "W: /sys/kernel/debug/devices_deferred has the following content:" >&2
  cat /sys/kernel/debug/devices_deferred >&2
fi

if [ "$OFFLINE" = "yes" ]; then
  echo "I: skipping the remaining checks because --offline was used" >&2
else
  if ! backend_repo_online_checks; then
    echo "E: running distro backend online repository checks failed" >&2
    exit 1
  fi

  bootloaderurl="https://source.mnt.re/reform/${BOOTLOADER_PROJECT}/-/jobs/artifacts/${BOOTLOADER_TAG}/raw/$(basename "$DTBPATH" .dtb)-flash.bin?job=build"
  bootloaderbin=$(mktemp)
  ret=0
  download_url_with_sha1 "$bootloaderurl" "$bootloaderbin" "$BOOTLOADER_SHA1" || ret=$?
  if [ "$ret" != 0 ]; then
    echo "E: download of $bootloaderurl failed" >&2
  else
    if [ ! -e /boot/flash.bin ]; then
      echo "W: /boot/flash.bin doesn't exist" >&2
      echo "W: You can download the latest version by running as root:" >&2
      echo "reform-flash-bootloader" >&2
    elif ! cmp --quiet /boot/flash.bin "$bootloaderbin"; then
      echo "W: /boot/flash.bin is not the latest bootloader" >&2
      echo "W: You can update it to the latest version by running as root:" >&2
      echo "reform-flash-bootloader" >&2
    fi
    bootloadersize=$(stat --format=%s "$bootloaderbin")

    if [ "$EMMC_BOOT" != false ]; then
      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=$FLASHBIN_OFFSET:$BOOTLOADER_OFFSET" "$bootloaderbin" "$realdev" 2>/dev/null; then
        echo "I: eMMC contains the latest bootloader version ${BOOTLOADER_TAG}" >&2
      else
        echo "W: eMMC does not contain latest bootloader" >&2
        echo "W: You can update it to the latest version by running as root:" >&2
        echo "reform-flash-bootloader emmc" >&2
        if [ "$EMMC_BOOT" = warn ]; then
          echo "I: note that updating the bootloader on eMMC on your platform is not without risk!" >&2
        fi
        if cmp --quiet --bytes="$((bootloadersize - FLASHBIN_OFFSET))" "--ignore-initial=0:$BOOTLOADER_OFFSET" /dev/zero "$realdev" 2>/dev/null; then
          echo "I: The space where the bootloader would've been on eMMC is all zeroes." >&2
        fi
      fi
    fi

    if [ "$SD_BOOT" != false ] && [ -e "/dev/$DEV_SD" ]; then
      if cmp --quiet --bytes="$((bootloadersize - FLASHBIN_OFFSET))" --ignore-initial="$FLASHBIN_OFFSET:$BOOTLOADER_OFFSET" "$bootloaderbin" "/dev/$DEV_SD" 2>/dev/null; then
        echo "I: SD-card contains the latest bootloader version ${BOOTLOADER_TAG}" >&2
      else
        echo "W: SD-Card does not contain latest bootloader" >&2
        echo "W: You can update it to the latest version by running as root:" >&2
        echo "reform-flash-bootloader sd" >&2
        if [ "$SD_BOOT" = warn ]; then
          echo "I: note that updating the bootloader on SD-card on your platform is not without risk!" >&2
        fi
        if cmp --quiet --bytes="$((bootloadersize - FLASHBIN_OFFSET))" "--ignore-initial=0:$BOOTLOADER_OFFSET" /dev/zero "/dev/$DEV_SD" 2>/dev/null; then
          echo "I: The space where the bootloader would've been on SD-Card is all zeroes." >&2
        fi
      fi
    fi
  fi
  rm "$bootloaderbin"

  case "$MODEL" in "MNT Reform 2 with LS1028A Module")
    mhdpfwbin=$(mktemp)
    if download_url_with_sha1 \
      "https://source.mnt.re/reform/reform-ls1028a-uboot/-/raw/main/ls1028a-mhdpfw.bin" \
      "$mhdpfwbin" "fa96b9aa59d7c1e9e6ee1c0375d0bcc8f8e5b78c"; then
      if [ ! -e /boot/ls1028a-mhdpfw.bin ]; then
        echo "W: /boot/ls1028a-mhdpfw.bin doesn't exist" >&2
        echo "W: You can download the latest version by running as root:" >&2
        echo "reform-flash-bootloader" >&2
      elif ! cmp --quiet /boot/ls1028a-mhdpfw.bin "$mhdpfwbin"; then
        echo "W: /boot/ls1028a-mhdpfw.bin is not the latest uboot" >&2
        echo "W: You can update it to the latest version by running as root:" >&2
        echo "reform-flash-bootloader" >&2
      fi
    else
      echo "E: download of ls1028a-mhdpfw.bin failed" >&2
    fi
    rm "$mhdpfwbin"
    ;;
  esac

fi
