#!/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

set -eu

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}] [--offline]" >&2
  echo >&2
  echo "Options:" >&2
  echo "  --help           Display this help and exit." >&2
  echo "  --mirror=MIRROR  Force MIRROR, either mntre.com or reform.debian.net" >&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=
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

if [ -n "$MIRROR" ] && [ "$MIRROR" != "mntre.com" ] && [ "$MIRROR" != "reform.debian.net" ]; then
  echo "E: invalid value for --mirror: $MIRROR -- only mntre.com and reform.debian.net are supported" >&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 \
    || grep --silent -F 'if [ "$(whoami)" = "root" ]; then reform-help --root; elif [ -z "$WAYLAND_DISPLAY" ]; then reform-help; fi' ~/.profile; then
    echo "E: Your ~/.profile contains an outdated line that attempts to print /etc/reform-help or run reform-help." >&2
    echo "E: Consider simply deleting that offending last line of your ~/.profile." >&2
  fi

  python3 - /usr/share/glib-2.0/schemas/20_reform.gschema.override <<'END'
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

  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 [ -z "$MIRROR" ] && grep --silent '^URIs: https://reform.debian.net/debian/\?$' /etc/apt/sources.list.d/reform*.sources 2>/dev/null; then
  echo "I: reform.debian.net is configured as a mirror in /etc/apt/sources.list.d" >&2
  echo "I: Assuming reform.debian.net stable mirror for this script" >&2
  echo "I: If this is incorrect, you can set the mirror to its default by re-running this script with --mirror=mntre.com"
  MIRROR="reform.debian.net"
fi

if [ -z "$MIRROR" ]; then
  MIRROR="mntre.com"
fi

if [ -z "$(apt-get indextargets)" ] && [ "$OFFLINE" != "yes" ]; then
  echo "E: reform-check needs a populated apt cache for some of its operation." >&2
  echo "E: re-run with --offline (disabling some checks) or choose to run 'apt update' now." >&2
  printf "Should reform-check run 'apt update' for you? [y/N]" >&2
  read -r response
  if [ "$response" != "y" ]; then
    echo "Exiting."
    exit 1
  fi
  apt-get update --error-on=any
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

echo "I: Contents of /proc/device-tree/model: $(cat /proc/device-tree/model)" >&2
echo "I: \`uname -a\` output: $(uname -a)" >&2
if dpkg-query --showformat '${db:Status-Status}\n' --show "linux-image-mnt-reform-arm64" 2>/dev/null | grep -q '^installed$'; then
  echo "I: Version of linux-image-mnt-reform-arm64: $(dpkg-query --show --showformat '${Version}' linux-image-mnt-reform-arm64)" >&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 linux-image-mnt-reform-arm64 as it is not installed" >&2
fi
echo "I: Version of reform-tools: $(dpkg-query --show --showformat '${Version}' reform-tools)" >&2
HUMAN_ROOT=
case $(findmnt --noheadings --evaluate --mountpoint / --output SOURCE) in
  "/dev/reformvg/root")
    pv_device="$(pvdisplay --noheadings --select vgname=reformvg --columns --options pv_name)"
    pv_device="${pv_device#  }" # remove whitespace prefix
    if [ "$pv_device" = "/dev/mapper/reform_crypt" ]; then
      luks_disk="$(lsblk --json -o PATH,PKNAME | jq -r '.blockdevices[] | select(.path == "/dev/mapper/reform_crypt") | .pkname')"
      if [ "$luks_disk" = "${DEV_SSD}" ]; then
        HUMAN_ROOT="LVM vg 'reformvg' on LUKS device 'reform_crypt' on SSD"
      else
        echo "W: reform_crypt LUKS device on unusual disk: /dev/$luks_disk" >&2
      fi
    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 /: $(findmnt --noheadings --evaluate --mountpoint / --output SOURCE) (${HUMAN_ROOT:-n.a.})" >&2
HUMAN_BOOT=
case $(findmnt --noheadings --evaluate --mountpoint /boot --output SOURCE) in
  "/dev/${DEV_MMC}"*) HUMAN_BOOT="eMMC" ;;
  "/dev/${DEV_SD}"*) HUMAN_BOOT="SD-card" ;;
esac
echo "I: Mount source of /boot: $(findmnt --noheadings --evaluate --mountpoint /boot --output SOURCE) (${HUMAN_BOOT})" >&2

if [ ! -e "/etc/flash-kernel/machine" ]; then
  # /etc/flash-kernel/machine not existing is only a potential problem
  # on imx8mq
  case "$(cat /proc/device-tree/model)" in
    "MNT Reform 2" | "MNT Reform 2 HDMI") echo "W: /etc/flash-kernel/machine does not exist" >&2 ;;
  esac
fi

if [ ! -e "/proc/device-tree/model" ]; then
  echo "E: /proc/device-tree/model does not exist" >&2
fi

if [ -e "/etc/flash-kernel/machine" ] && [ -e "/proc/device-tree/model" ] && [ "$(cat /proc/device-tree/model)" != "$(cat /etc/flash-kernel/machine)" ]; then
  echo "E: your currently loaded dtb is not the one referenced by flash-kernel" >&2
  echo "E: contents of /proc/device-tree/model: $(cat /proc/device-tree/model)" >&2
  echo "E: contents of /etc/flash-kernel/machine: $(cat /etc/flash-kernel/machine)" >&2
fi

case "$MIRROR" in
  mntre.com) aptprefcontent="Package: *\nPin: release n=reform, l=reform\nPin-Priority: 990\n" ;;
  reform.debian.net) aptprefcontent="Package: *\nPin: origin \"reform.debian.net\"\nPin-Priority: 999\n" ;;
esac
if [ ! -e /etc/apt/preferences.d/reform.pref ]; then
  echo "E: /etc/apt/preferences.d/reform.pref doesn't exist" >&2
  echo "E: you should not install packages on this system unless you know what you are doing" >&2
  echo "E: /etc/apt/preferences.d/reform.pref should contain the following lines:" >&2
  printf "$aptprefcontent" >&2
else
  if ! printf "$aptprefcontent" | cmp --quiet - /etc/apt/preferences.d/reform.pref; then
    echo "W: unexpected content in /etc/apt/preferences.d/reform.pref:" >&2
    printf "$aptprefcontent" | diff -u - /etc/apt/preferences.d/reform.pref || true
    echo "W: you should not install packages on this system unless you know what you are doing" >&2
  fi
fi

for META in reform-desktop-full reform-desktop-minimal; do
  # if meta package is installed, we don't need to check its Depends
  RELATIONS="Recommends Suggests"
  if ! dpkg-query --showformat '${db:Status-Status}\n' --show "$META" 2>/dev/null | grep -q '^installed$'; then
    echo "W: MNT Reform Desktop meta-package is not installed: $META" >&2
    RELATIONS="Depends $RELATIONS"
  fi
  for REL in $RELATIONS; do
    OIFS=$IFS
    IFS=',' # split field by comma
    for PKG in $(apt-cache show --no-all-versions $META | sed -ne 's/^'"$REL"': \(.*\)/\1/p'); do
      PKG="${PKG## }" # strip whitespace
      if ! dpkg-query --showformat '${db:Status-Status}\n' --show "$PKG" 2>/dev/null | grep -q '^installed$'; then
        echo "W: $REL of $META is not installed: $PKG" >&2
      fi
    done
    IFS=$OIFS
  done
done

if [ -z "$(findmnt --fstab --noheadings --evaluate --mountpoint / --output SOURCE)" ]; then
  echo "E: your /etc/fstab does not have an entry for /" >&2
  echo "E: your / device probably is: $(findmnt --noheadings --evaluate --mountpoint / --output SOURCE)" >&2
  echo "E: add this to your /etc/fstab:" >&2
  echo "$(findmnt --noheadings --evaluate --mountpoint / --output SOURCE) / auto errors=remount-ro 0 1" >&2
fi

if [ -z "$(findmnt --fstab --noheadings --evaluate --mountpoint /boot --output SOURCE)" ]; then
  echo "E: your /etc/fstab does not have an entry for /boot" >&2
  if [ "$EMMC_BOOT" = true ]; then
    echo "E: for eMMC booting, add:" >&2
    echo "/dev/${DEV_MMC}p1 /boot auto errors=remount-ro 0 1" >&2
  fi
  if [ "$SD_BOOT" = true ]; then
    echo "E: for SD-Card booting, add:" >&2
    echo "/dev/${DEV_SD}p1 /boot auto errors=remount-ro 0 1" >&2
  fi
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 sysimage-v4 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/flash-kernel/machine ]; then
  # /etc/flash-kernel/machine not existing is only a potential problem
  # on imx8mq
  case "$(cat /proc/device-tree/model)" in
    "MNT Reform 2" | "MNT Reform 2 HDMI")
      echo "E: /etc/flash-kernel/machine doesn't exist" >&2
      echo "E: It should contain either 'MNT Reform 2' (for single display) or 'MNT Reform 2 HDMI' (for dual display)." >&2
      echo "E: You can run reform-display-config as root to create a working version." >&2
      ;;
  esac
else
  case "$(cat /etc/flash-kernel/machine)" in
    "MNT Reform 2") : ;;
    "MNT Reform 2 HDMI") : ;;
    "MNT Reform 2 with BPI-CM4 Module") echo "W: /etc/flash-kernel/machine is not needed on A311D. Consider removing it." >&2 ;;
    "MNT Reform 2 with LS1028A Module") echo "W: /etc/flash-kernel/machine is not needed on LS1028A. Consider removing it." >&2 ;;
    *) echo "E: unexpected content in /etc/flash-kernel/machine" >&2 ;;
  esac
fi

flashkerneldefaultcontent="LINUX_KERNEL_CMDLINE=\"\"\nLINUX_KERNEL_CMDLINE_DEFAULTS=\"\"\n"
if [ ! -e /etc/default/flash-kernel ]; then
  echo "E: /etc/default/flash-kernel doesn't exist" >&2
  echo "E: /etc/default/flash-kernel should contain the following lines:" >&2
  printf "$flashkerneldefaultcontent" >&2
else
  if ! printf "$flashkerneldefaultcontent" | cmp --quiet - /etc/default/flash-kernel; then
    echo "W: unexpected content in /etc/default/flash-kernel:" >&2
    printf "$flashkerneldefaultcontent" | diff -u - /etc/default/flash-kernel || true
  fi
fi

if [ -e /etc/flash-kernel/preboot.d/00reform2_preboot ]; then
  if printf "# place here any u-boot commands to be executed before boot\n" | cmp --quiet - /etc/flash-kernel/preboot.d/00reform2_preboot; then
    echo "E: /etc/flash-kernel/preboot.d/00reform2_preboot contains default content overriding /usr/share/flash-kernel/preboot.d/00reform2_preboot" >&2
    echo "E: consider deleting /etc/flash-kernel/preboot.d/00reform2_preboot in favour of /usr/share/flash-kernel/preboot.d/00reform2_preboot" >&2
  else
    echo "W: your custom /etc/flash-kernel/preboot.d/00reform2_preboot is overriding /usr/share/flash-kernel/preboot.d/00reform2_preboot" >&2
  fi
fi

if [ -e /etc/flash-kernel/ubootenv.d/00reform2_ubootenv ]; then
  if printf '# setenv bootpart "1"\n# setenv prefix "/"\n# setenv kernel_addr_r "0x40480000"\n# setenv fdt_addr_r "0x50000000"\n# setenv ramdisk_addr_r "0x51000000"\n' | cmp --quiet - /etc/flash-kernel/ubootenv.d/00reform2_ubootenv; then
    echo "E: /etc/flash-kernel/ubootenv.d/00reform2_ubootenv contains default content overriding /usr/share/flash-kernel/ubootenv.d/00reform2_ubootenv" >&2
    echo "E: consider deleting /etc/flash-kernel/ubootenv.d/00reform2_ubootenv in favour of /usr/share/flash-kernel/ubootenv.d/00reform2_ubootenv" >&2
  else
    echo "W: your custom /etc/flash-kernel/ubootenv.d/00reform2_ubootenv is overriding /usr/share/flash-kernel/ubootenv.d/00reform2_ubootenv"
  fi
fi

if command -v systemctl >/dev/null 2>&1 \
  && systemctl is-active --quiet greetd \
  && test -e /etc/greetd/config.toml \
  && grep --quiet '^ *command *= *["'"'"']/usr/bin/tuigreet *' /etc/greetd/config.toml; then
  if [ -e /etc/flash-kernel/ubootenv.d/00reform2_tuigreet_loglevel ]; then
    # shellcheck disable=SC2016
    if ! echo 'setenv bootargs "${bootargs} loglevel=3"' | cmp --quiet - /etc/flash-kernel/ubootenv.d/00reform2_tuigreet_loglevel; then
      echo "I: /etc/flash-kernel/ubootenv.d/00reform2_tuigreet_loglevel exists but with the wrong content." >&2
      echo 'I: it should contain this: setenv bootargs "${bootargs} loglevel=3'
    fi
  else
    # shellcheck disable=SC2016
    echo 'I: your system is booting using greetd with tuigreet. You may want to put the following line into your /etc/flash-kernel/ubootenv.d/00reform2_tuigreet_loglevel: setenv bootargs "${bootargs} loglevel=3' >&2
    echo "I: Then run 'sudo flash-kernel' to regenerate your /boot/boot.scr. This will do away with your kernel overwriting your login prompt" >&2
  fi
else
  # shellcheck disable=SC2016
  if [ -e /etc/flash-kernel/ubootenv.d/00reform2_tuigreet_loglevel ] && echo 'setenv bootargs "${bootargs} loglevel=3"' | cmp --quiet - /etc/flash-kernel/ubootenv.d/00reform2_tuigreet_loglevel; then
    echo "W: you do not seem to boot using tuigreet but you the following file sets your loglevel to 3: /etc/flash-kernel/ubootenv.d/00reform2_tuigreet_loglevel -- you may consider removing it and re-running 'sudo flash-kernel'" >&2
  fi
fi

initramfstoolsmodulescontent="pwm_imx27\nnwl-dsi\nti-sn65dsi86\nimx-dcss\npanel-edp\nmux-mmio\nmxsfb\nusbhid\nimx8mq-interconnect\n"
if [ -e /etc/initramfs-tools/modules ] && printf "$initramfstoolsmodulescontent" | cmp --quiet - /etc/initramfs-tools/modules; then
  echo "W: /etc/initramfs-tools/modules contains default content superseded by /usr/share/initramfs-tools/modules.d/reform.conf" >&2
  echo "W: consider restoring /etc/initramfs-tools/modules to its original state by running:" >&2
  echo "sed '/^###/d' /usr/share/initramfs-tools/modules | sudo tee /etc/initramfs-tools/modules" >&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

if grep --quiet '^root::' /etc/shadow; then
  echo "E: root account has no password (maybe run passwd -l root)" >&2
fi

if [ ! -e /etc/skel/.profile ]; then
  echo "E: /etc/skel/.profile doesn't exist" >&2
  echo "E: install the package bash to create it" >&2
else
  # 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' /etc/skel/.profile \
    || grep --silent -F 'if [ $(whoami) = "root" ]; then cat /etc/reform-root-help; elif [ -z $WAYLAND_DISPLAY ]; then cat /etc/reform-help; fi' /etc/skel/.profile \
    || grep --silent -F 'if [ "$(whoami)" = "root" ]; then cat /etc/reform-root-help; elif [ -z "$WAYLAND_DISPLAY" ]; then cat /etc/reform-help; fi' /etc/skel/.profile \
    || grep --silent -F 'if [ "$(whoami)" = "root" ]; then reform-help --root; elif [ -z "$WAYLAND_DISPLAY" ]; then reform-help; fi' /etc/skel/.profile; then
    echo "E: Your /etc/skel/.profile contains an outdated line that attempts to print /etc/reform-help or run reform-help." >&2
    echo "E: Consider simply deleting that offending last line of your /etc/skel/.profile." >&2
  fi
fi

if [ -n "$(dpkg --verify reform-tools)" ]; then
  echo "I: the following files differ from how they are shipped by reform-tools (ignore /var/lib/alsa/asound.state):" >&2
  dpkg --verify reform-tools
fi

if dpkg-query --showformat '${db:Status-Status}\n' --show "linux-image-arm64" 2>/dev/null | grep -q '^installed$'; then
  echo "W: The deprecated meta-package linux-image-arm64 is installed." >&2
  if dpkg-query --showformat '${db:Status-Status}\n' --show "linux-image-mnt-reform-arm64" 2>/dev/null | grep -q '^installed$'; then
    echo "W: Since the new meta-package linux-image-mnt-reform-arm64 is installed," >&2
    echo "W: the old meta-package linux-image-arm64 should be removed." >&2
  else
    echo "W: Please install the new meta-package linux-image-mnt-reform-arm64" >&2
    echo "W: and remove the old meta-package linux-image-arm64." >&2
  fi
  if ! dpkg-query --showformat '${Version}' --show linux-image-arm64 | grep --quiet reform; then
    echo "E: the currently installed package linux-image-arm64 does not come with Reform patches" >&2
  fi
fi

if ! dpkg-query --showformat '${db:Status-Status}\n' --show "linux-image-mnt-reform-arm64" 2>/dev/null | grep -q '^installed$'; then
  echo "E: linux-image-mnt-reform-arm64 is not installed" >&2
fi

if ! dpkg-query --showformat '${db:Status-Status}\n' --show "linux-headers-mnt-reform-arm64" 2>/dev/null | grep -q '^installed$'; then
  echo "E: linux-headers-mnt-reform-arm64 is not installed -- cannot compile reform2_lpc module" >&2
fi

for file in /boot/initrd.img-*-reform2-arm64 /boot/vmlinuz-*-reform2-arm64; do
  if [ ! -e "$file" ]; then
    continue
  fi
  echo "I: file from deprecated kernel flavour found: $file" >&2
done

for file in /boot/initrd.img-*-mnt-reform-arm64 /boot/vmlinuz-*-mnt-reform-arm64; do
  suffix="${file##/boot/}"
  suffix="${suffix##initrd.img-}"
  suffix="${suffix##vmlinuz-}"
  if ! dpkg-query --showformat '${db:Status-Status}\n' --show "linux-image-$suffix" 2>/dev/null | grep -q '^installed$'; then
    echo "I: $file does not belong to any installed kernel package" >&2
  fi
done

if ! dpkg-query --showformat '${db:Status-Status}\n' --show "linux-image-$(uname -r)" 2>/dev/null | grep -q '^installed$'; then
  echo "E: the currently running kernel is not installed as a package" >&2
fi
if ! uname --kernel-version | grep --quiet --fixed-strings " $(dpkg-query --show --showformat '${Version}' linux-image-mnt-reform-arm64) "; then
  echo "E: the currently running kernel is not the one provided by linux-image-mnt-reform-arm64" >&2
fi

if [ "$MIRROR" = "reform.debian.net" ] && dpkg-query --showformat '${db:Status-Status}\n' --show "reform-qcacld2" 2>/dev/null | grep -q '^installed$'; then
  echo "E: Having reform-qcacld2 on a system configured to use packages for Debian stable from reform.debian.net will attempt installing the kernel package from the MNT repositories in the kernel postinstallation hook" >&2
  echo "W: Consider replacing reform-qcacld2 with ezurio-qcacld-2.0-dkms for Debian stable and stable-backports kernels from reform.debian.net" >&2
fi

if [ "$MIRROR" = "mntre.com" ] && ! dpkg-query --showformat '${db:Status-Status}\n' --show "reform-qcacld2" 2>/dev/null | grep -q '^installed$'; then
  case "$(cat /proc/device-tree/model)" in "MNT Pocket Reform with i.MX8MP Module.conf")
    echo "E: For the official MNT Debian on Pocket Reform with i.MX8MP, the reform-qcacld2 package needs to be installed for working wifi" >&2
    ;;
  esac
fi

if [ ! -e /boot/boot.scr ]; then
  echo "E: /boot/boot.scr doesn't exist" >&2
  echo "E: run 'sudo flash-kernel' to create it" >&2
elif ! grep --quiet "setenv fk_kvers '$(uname -r)'" /boot/boot.scr; then
  echo "E: /boot/boot.scr doesn't reference the currently running kernel" >&2
fi

if [ ! -e "/boot/vmlinuz-$(uname -r)" ]; then
  echo "E: no vmlinuz in /boot for the currently running kernel" >&2
fi

if [ ! -e "/boot/initrd.img-$(uname -r)" ]; then
  echo "E: no initrd.img in /boot for the currently running kernel" >&2
fi

if [ ! -e "/boot/dtb-$(uname -r)" ]; then
  echo "E: no dtb-* symlink for the currently running kernel" >&2
  echo "E: run 'sudo flash-kernel' to create it" >&2
elif [ ! -e "/boot/dtbs/$(uname -r)/$DTBPATH" ]; then
  echo "E: device tree file $DTBPATH is missing from /boot/dtbs" >&2
elif [ "$(readlink "/boot/dtb-$(uname -r)")" != "dtbs/$(uname -r)/$DTBPATH" ]; then
  echo "E: /boot/dtb-$(uname -r) symlink does not reference dtbs/$(uname -r)/$DTBPATH but: $(readlink "/boot/dtb-$(uname -r)")" >&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 [ ! -e "/usr/lib/modules/$(uname -r)/updates/dkms/reform2_lpc.ko" ] \
  && [ ! -e "/usr/lib/modules/$(uname -r)/updates/dkms/reform2_lpc.ko.xz" ]; then
  echo "E: /usr/lib/modules/$(uname -r)/updates/dkms/reform2_lpc.ko{.xz} does not exist" >&2
fi

worddiff() {
  for word in $1; do
    case $2 in
      "$word" | "$word "* | *" $word" | *" $word "*) : ;;
      *) echo "$word" ;;
    esac
  done
}
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

if ! dpkg-query --showformat '${db:Status-Status}\n' --show "linux-headers-$(uname -r)" 2>/dev/null | grep -q '^installed$'; then
  echo "E: the linux header package linux-headers-$(uname -r) for the currently running kernel is not installed" >&2
fi

for f in mntre reform_bookworm reform_bookworm-backports; do
  file="/etc/apt/sources.list.d/${f}.sources"
  if [ ! -e "$file" ]; then
    continue
  fi
  if [ "$(stat -c %a "$file")" != 666 ]; then
    # nothing to do
    continue
  fi
  echo "E: $file has insecure permissions 0666, consider a chmod 644" >&2
done
for f in . firefox firefox/syspref.js motd-full motd-rescue profile.d profile.d/reform.sh profile.d/reform-setup.sh; do
  file="/etc/$f"
  if [ ! -e "$file" ]; then
    continue
  fi
  # only process world-writable files
  if [ -z "$(find "$file" -maxdepth 0 \( \! -type l \) -perm /o+w)" ]; then
    continue
  fi
  echo "E: $file has insecure permissions (it is world-writable)" >&2
done
if [ -e /etc/skel ] && [ "$(stat -c %a /etc/skel)" = "777" ]; then
  echo "E: /etc/skel has insecure permissions 0777, consider a chmod -R g-w,o-rw" >&2
fi
if [ -n "$(find /etc \( \! -type l \) -perm /o+w)" ]; then
  echo "E: the following files in /etc are world-writable, consider removing world-writable permissions:" >&2
  find /etc \( \! -type l \) -perm /o+w >&2
fi
if [ -n "$(find /root \( \! -type l \) -perm /o+w)" ]; then
  echo "E: the following files in /root are world-writable, consider removing world-writable permissions:" >&2
  find /root \( \! -type l \) -perm /o+w >&2
fi

case "$(cat /proc/device-tree/model)" in "MNT Reform 2" | "MNT Reform 2 HDMI")
  if [ ! -e /etc/u-boot-menu/conf.d ]; then
    echo "W: /etc/u-boot-menu/conf.d does not exist -- create it by running reform-display-config" >&2
  fi
  if [ ! -e /etc/u-boot-menu/conf.d/reform.conf ]; then
    echo "W: /etc/u-boot-menu/conf.d/reform.conf does not exist -- create it by running reform-display-config" >&2
  else
    case "$(cat /proc/device-tree/model)" in
      "MNT Reform 2")
        reformconfcontent="# the content of this file is auto-generated by reform-display-config\nU_BOOT_FDT=/freescale/imx8mq-mnt-reform2.dtb\n"
        ;;
      "MNT Reform 2 HDMI")
        reformconfcontent="# the content of this file is auto-generated by reform-display-config\nU_BOOT_FDT=/freescale/imx8mq-mnt-reform2-hdmi.dtb\n"
        ;;
    esac
    if ! printf "$reformconfcontent" | cmp --quiet - /etc/u-boot-menu/conf.d/reform.conf; then
      echo "W: unexpected content in /etc/u-boot-menu/conf.d/reform.conf:" >&2
      printf "$reformconfcontent" | diff -u - /etc/u-boot-menu/conf.d/reform.conf || true
      echo "W: re-run reform-display-config for the corrent content" >&2
    fi
  fi
  ;;
esac

if [ "$OFFLINE" = "yes" ]; then
  echo "I: skipping the remaining checks because --offline was used" >&2
else
  # shellcheck disable=SC2016
  case "$MIRROR" in mntre.com)
    if [ "$(apt-get indextargets 'Created-By: Packages' 'Repo-URI: https://mntre.com/reform-debian-repo/' --format '$(RELEASE)')" != reform ]; then
      echo "E: the reform repository is not known to apt" >&2
      echo "E: add the following line to your /etc/apt/sources.list to fix this" >&2
      echo "deb [arch=arm64 trusted=yes] https://mntre.com/reform-debian-repo reform main" >&2
    fi
    if [ -n "$(apt-get indextargets 'Created-By: Packages' 'Repo-URI: https://reform.debian.net/debian/' --format '$(RELEASE)')" ]; then
      echo "E: you have the reform.debian.net repository enabled while also using the mntre.com mirror. Consider choosing one or the other but not both." >&2
    fi
    ;;
  reform.debian.net)
    release="$(apt-get indextargets 'Created-By: Packages' 'Repo-URI: https://reform.debian.net/debian/' --format '$(RELEASE)')"
    case "$release" in
      "") echo "E: unable to obtain release name for reform.debian.net repository" >&2 ;;
      bookworm*) : ;;
      trixie*) : ;;
      *) echo "E: unknown reform.debian.net repository release name: $release" >&2 ;;
    esac
    if [ "$(apt-get indextargets 'Created-By: Packages' 'Repo-URI: https://mntre.com/reform-debian-repo/' --format '$(RELEASE)')" = reform ]; then
      echo "E: you have the mntre.com repository enabled while also using the reform.debian.net mirror. Consider choosing one or the other but not both." >&2
    fi
    ;;
  *)
    echo "invalid mirror: $MIRROR" >&2
    exit 1
    ;;
  esac

  # on a311d we need non-free-firmware
  # shellcheck disable=SC2016
  if [ "$NEED_NONFREE" = true ] && ! apt-get indextargets 'Created-By: Packages' 'Origin: Debian' 'Repo-URI: http://deb.debian.org/debian/' --format '$(COMPONENT)' | sort -u | grep --silent non-free-firmware; then
    echo "W: you do not have non-free-firmware enabled" >&2
    echo "W: this is required to install non-free firmware blobs that are required for platforms like Banana Pi A311D" >&2
    echo "W: you can add a line like this to your /etc/apt/sources.list:" >&2
    echo "deb http://deb.debian.org/debian unstable non-free-firmware" >&2
  fi

  ubooturl="https://source.mnt.re/reform/${UBOOT_PROJECT}/-/jobs/artifacts/${UBOOT_TAG}/raw/$(basename "$DTBPATH" .dtb)-flash.bin?job=build"
  ubootbin=$(mktemp)
  ret=0
  /usr/lib/apt/apt-helper download-file "$ubooturl" "$ubootbin" "SHA1:$UBOOT_SHA1" >/dev/null || ret=$?
  if [ "$ret" != 0 ]; then
    echo "E: download of $ubooturl 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-uboot" >&2
    elif ! cmp --quiet /boot/flash.bin "$ubootbin"; then
      echo "W: /boot/flash.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-uboot" >&2
    fi
    ubootsize=$(stat --format=%s "$ubootbin")

    if [ "$EMMC_BOOT" = true ]; then
      if cmp --quiet --bytes="$((ubootsize - FLASHBIN_OFFSET))" "--ignore-initial=$FLASHBIN_OFFSET:$UBOOT_OFFSET" "$ubootbin" "/dev/${DEV_MMC}boot0" 2>/dev/null; then
        echo "I: eMMC contains the latest u-boot version ${UBOOT_TAG}" >&2
      else
        echo "W: eMMC does not contain latest uboot" >&2
        echo "W: You can update it to the latest version by running as root:" >&2
        echo "reform-flash-uboot emmc" >&2
      fi
    fi

    if [ "$SD_BOOT" = true ] && [ -e "/dev/$DEV_SD" ]; then
      if cmp --quiet --bytes="$((ubootsize - FLASHBIN_OFFSET))" --ignore-initial="$FLASHBIN_OFFSET:$UBOOT_OFFSET" "$ubootbin" "/dev/$DEV_SD" 2>/dev/null; then
        echo "I: SD-card contains the latest u-boot version ${UBOOT_TAG}" >&2
      else
        echo "W: SD-Card does not contain latest uboot" >&2
        echo "W: You can update it to the latest version by running as root:" >&2
        echo "reform-flash-uboot sd" >&2
      fi
    fi
  fi
  rm "$ubootbin"

  case "$(cat /proc/device-tree/model)" in "MNT Reform 2 with LS1028A Module")
    mhdpfwbin=$(mktemp)
    /usr/lib/apt/apt-helper download-file \
      "https://source.mnt.re/reform/reform-ls1028a-uboot/-/raw/main/ls1028a-mhdpfw.bin" \
      "$mhdpfwbin" "SHA1:fa96b9aa59d7c1e9e6ee1c0375d0bcc8f8e5b78c" >/dev/null
    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-uboot" >&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-uboot" >&2
    fi
    rm "$mhdpfwbin"
    ;;
  esac

  if dpkg-query --showformat '${db:Status-Status}\n' --show "linux-image-arm64" 2>/dev/null | grep -q '^installed$'; then
    case "$MIRROR" in mntre.com)
      if ! apt-cache policy linux-image-arm64 | grep --quiet mntre.com; then
        echo "E: the linux-image-arm64 package cannot come from the MNT repos" >&2
      fi
      ;;
    reform.debian.net)
      if ! apt-cache policy linux-image-arm64 | grep --quiet /reform.debian.net/; then
        echo "E: the linux-image-arm64 package cannot come from the reform.debian.net repos" >&2
      fi
      ;;
    *)
      echo "invalid mirror: $MIRROR" >&2
      exit 1
      ;;
    esac
  fi

  if dpkg-query --showformat '${db:Status-Status}\n' --show "linux-image-mnt-reform-arm64" 2>/dev/null | grep -q '^installed$'; then
    case "$MIRROR" in mntre.com)
      if ! apt-cache policy linux-image-mnt-reform-arm64 | grep --quiet mntre.com; then
        echo "E: the linux-image-mnt-reform-arm64 package cannot come from the MNT repos" >&2
      fi
      ;;
    reform.debian.net)
      if ! apt-cache policy linux-image-mnt-reform-arm64 | grep --quiet /reform.debian.net/; then
        echo "E: the linux-image-mnt-reform-arm64 package cannot come from the reform.debian.net repos" >&2
      fi
      ;;
    *)
      echo "invalid mirror: $MIRROR" >&2
      exit 1
      ;;
    esac
  fi
fi
