#!/bin/bash

ulimit -s unlimited

OPTDIR=/var/opt/comb
DEF_IMG_NAME=comb-ns

LOCALES="af_ZA de_DE en_GB en_US en_ZA es_ES fr_FR it_IT nr_ZA nso_ZA pt_PT ss_ZA st_ZA tn_ZA ts_ZA ve_ZA xh_ZA zu_ZA"
LOCALE_BASE="locale-base-en-us locale-base-en-za locale-base-nr-za locale-base-nso-za locale-base-ss-za locale-base-st-za locale-base-tn-za locale-base-ts-za locale-base-ve-za locale-base-zu-za"

MARK_PKG="packagegroup*"

KERNEL_PKG="packagegroup-comb-kernel kernel-modules kernel-module-* kernel-image-*"
KERNEL_PKG_RASPI="bootfiles kernel-devicetree cryptodev-module rpi-cmdline rpi-config";

ARCH=$(cut -d- -f1 /etc/rpm/platform)
CODENAME=$(lsb_release -c |cut -f2)
POKY=$(lsb_release -r |cut -f2)
ARCH_NAME=$(echo ${ARCH} |tr '_' '-')
ARCH_DIR=$(echo ${ARCH_NAME} |sed -e "s/raspberrypi/raspi/")
REPO="oe-remote-repo"
KERN_VER=${KERN_VER=$(uname -r)}
BASEURL="https://honeycomb.comb-communications.com"

TMPDEV="/dev/comb-ns-root"

if [ -e ~/${DEF_IMG_NAME} ] || [ ! -d ${OPTDIR} ];then
  DEF_IMG=~/${DEF_IMG_NAME}
 else
  if [ ! -d ${OPTDIR}/${ARCH_DIR}/${DEF_IMG_NAME} ];then
    mkdir -p ${OPTDIR}/${ARCH_DIR}/${DEF_IMG_NAME}
  fi;
  DEF_IMG=${OPTDIR}/${ARCH_DIR}/${DEF_IMG_NAME}
fi;

kernel_repo(){
  if [ ! -e ${1}/var/cache/dnf/${REPO}-${ARCH_NAME}-${CODENAME}-${ARCH}_kernel.solv ];then
    (cat <<__EOF__
[${REPO}-${ARCH_NAME}-${CODENAME}-${ARCH}_kernel]
name=OE Remote Repo: ${ARCH_NAME} ${CODENAME} ${ARCH}_kernel
baseurl=${BASEURL}/${ARCH_NAME}/${CODENAME}/${ARCH}_kernel
gpgcheck=0

__EOF__
    ) > ${1}/etc/yum.repos.d/${REPO}-${ARCH_NAME}-${CODENAME}-kernel.repo
  fi;
}

mount_sys(){
  for sysdir in dev proc sys run;do
    if [ ! -d ${1}/${sysdir} ];then
      mkdir ${1}/${sysdir}
    fi;
  done;
  mount -t devtmpfs devfs ${1}/dev
  mount -t sysfs sysfs ${1}/sys
  mount -t proc proc ${1}/proc
  mount -t tmpfs none ${1}/run

  if [ ! -d ${1}/var/volatile ];then
    mkdir -p ${1}/var/volatile
  fi;
  mount -t tmpfs none ${1}/var/volatile/
  for voldir in tmp log;do
    if [ ! -d ${1}/var/volatile/${voldir} ];then
      mkdir ${1}/var/volatile/${voldir}
    fi;
  done
  mkdir -p ${1}/run/lock
  mkdir -p ${1}/run/resolvconf
  mount -t devpts none ${1}/dev/pts
}

mk_locale(){
  for locale in ${LOCALES};do
    localedef --replace --add-to-archive --prefix=${1}/ -f UTF-8  ${1}/usr/lib/locale/${locale}
  done

  localedef --replace --add-to-archive --prefix=${1}/ -f iso-8859-1 ${1}/usr/lib/locale/fr_FR.ISO-8859-1
  localedef --replace --add-to-archive --prefix=${1}/ -f iso-8859-2 ${1}/usr/lib/locale/pl_PL.ISO-8859-2
  localedef --replace --add-to-archive --prefix=${1}/ -f iso-8859-9 ${1}/usr/lib/locale/tr_TR.ISO-8859-9
  localedef --replace --add-to-archive --prefix=${1}/ -f euc-jp  ${1}/usr/lib/locale/ja_JP.EUC-JP
  localedef --replace --add-to-archive --prefix=${1}/ -f big5-hkscs  ${1}/usr/lib/locale/zh_HK.BIG5-HKSCS
}

kern_depmod(){
  for kver in $(ls ${1}/lib/modules/);do
    depmod -b ${1}/ -a ${kver}
  done
}

kern_quick_install(){
  dnf ${DNF_OPT} --destdir=${1} --downloadonly install kernel-modules
  (rpm --root=${2}/ --replacefiles --noscripts -i ${1}/*.rpm && rm ${1}/*.rpm) 2>/dev/null

  dnf ${DNF_OPT} --destdir=${1} --downloadonly install ${KERNEL_PKG}
  (rpm --root=${2}/ --replacefiles --noscripts -i ${1}/*.rpm && rm ${1}/*.rpm) 2>/dev/null

  kern_depmod ${2}
}

kern_quick_update(){
  dnf ${DNF_OPT} --destdir=${1} --downloadonly update kernel-module*
  (rpm --root=${2}/ --replacefiles --noscripts --replacefiles --replacepkgs -U ${1}/*.rpm && rm ${1}/*.rpm) 2>/dev/null

  dnf ${DNF_OPT} --destdir=${1} --downloadonly update ${KERNEL_PKG}
  (rpm --root=${2}/ --replacefiles --noscripts --replacefiles --replacepkgs -U ${1}/*.rpm && rm ${1}/*.rpm) 2>/dev/null

  kern_depmod ${2}
}

check_poky() {
  case ${1} in
    "3.1.9" |"3.1.16" | "3.1.22")
      return 0
      ;;
    *)
      return 1
      ;;
  esac;
}

post_install(){
  if [ ! -e ${1}/usr/lib/locale/locale-archive ];then
    mk_locale ${1}
  fi;

  if [ ! -e ${1}/boot/config.txt ] && [ -e ${1}/boot/config.orig ];then
    (grep -vE "^(dtoverlay|#|$)" ${1}/boot/config.orig
    grep -E "^dtoverlay" ${1}/boot/config.orig) > ${1}/boot/config.txt
  fi;

  if [ ! -e ${1}/boot/cmdline.txt ] && [ -e ${1}/boot/cmdline.orig ];then
    install -m 0644 ${1}/boot/cmdline.orig ${1}/boot/cmdline.txt
  fi;

  rm -f  ${1}/etc/*- ${1}/etc/.pwd.lock
  if ! grep vm.min_free_kbytes ${1}/etc/sysctl.conf >/dev/null ;then
    printf '\nvm.min_free_kbytes = 8192\n' >> ${1}/etc/sysctl.conf
  fi

  #Empty locale files to make sure they installed
  dnf ${DNF_OPT} install ${LOCALE_BASE} \
	`dnf list |grep -E "^(glibc|gtk\+3)-locale-(en|en-za|en-gb|en-us|fr|de|pt|zu|af|es|it|nr|nso|ss|st|tn|ts|ve|xh|zu)\." |awk '{printf "%s ",$1}'`

  if [ "${1}" ] && [ "${1}" != "/" ];then
    sed -i '/^$/d' ${1}/usr/lib/ssl-1.1/certs/ca-certificates.crt
  fi;

  if [ ! -e ${1}/usr/share/icons/Adwaita/icon-theme.cache ];then
    dnf ${DNF_OPT} reinstall adwaita-icon-theme* && dnf ${DNF_OPT} install adwaita-icon-theme*
  fi;

  if [ ! -e ${1}/etc/timestamp ];then
    date -u +%4Y%2m%2d%2H%2M%2S  > ${1}/etc/timestamp
  fi;

  if [ ! -d ${1}/mnt/legato ];then
    mkdir -p ${1}/mnt/legato
  fi;

  check_poky ${POKY}
}

kern_update() {
    DLDIR=$(mktemp -d -p ~ rpmdl-XXXXXXXXX)
    kern_quick_update ${DLDIR} ${1}
    kern_quick_install ${DLDIR} ${1}

    if [ "${DLDIR}" ] && [ -d ${DLDIR} ];then
       rm -rf ${DLDIR}
    fi;
}

run_update() {
    echo "Update packages"
    kern_update ${1}
    dnf ${DNF_OPT} --exclude legato --exclude bootfiles --exclude kernel-image-* --exclude kernel-devicetree update
    dnf ${DNF_OPT} update legato

    post_install ${1}

    if [ ! "${1}" ] && [ -e /run/initctl ];then
      echo "Rebooting"
      /sbin/reboot
    fi;
}

dnf_update() {
  echo "Checking DB"
  if ! rpm --root=${1}/ --verifydb;then
    rpm --root=${1}/ --rebuilddb;
  fi;

  echo "Checking Install"
  if ! rpm --root=${1}/ -q packagegroup-comb >/dev/null;then
    kern_update ${1}
    dnf  ${DNF_OPT} install packagegroup-comb
    run_update ${1}
  fi

  echo "Checking App"
  if ! rpm --root=${1}/ -q packagegroup-comb-legato >/dev/null ;then
    kern_update ${1}
    dnf  ${DNF_OPT} install legato
    run_update ${1}
  fi

  echo "Checking updates"
  kernel_repo ${1}
  dnf ${DNF_OPT} --refresh check-update
  if [ $? -eq 100 ];then
    run_update ${1}
   else
    post_install ${1}
  fi

  if rpm --root=${1}/ -q packagegroup-comb-dunfell >/dev/null;then
    dnf ${DNF_OPT} --noautoremove erase packagegroup-comb-dunfell
  fi;
  dnf ${DNF_OPT} mark install ${MARK_PKG}
}

mkroot_base(){
  DLDIR=$(mktemp -d -p ~ rpmdl-XXXXXXXXX)

  echo "Download core rootfs files (${DLDIR})"
  dnf ${DNF_OPT} --destdir=${DLDIR} --downloadonly install base-files sysvinit busybox

  echo "Install core rootfs files without scripts"
  (rpm --root=${1} --noscripts -i ${DLDIR}/*.rpm && rm -rf ${1}/var/lib/rpm) 2>/dev/null

  echo "Install core rootfs files with scripts"
  dnf ${DNF_OPT} install base-files busybox util-linux-mountpoint util-linux-nologin procps
  dnf ${DNF_OPT} install sysvinit shadow
  dnf ${DNF_OPT} --destdir=${DLDIR} --downloadonly clean packages

  echo "Install kernel/kernel modules without scripts for each module"
  kern_quick_install ${DLDIR} ${1}

  if [ "${DLDIR}" ] && [ -d ${DLDIR} ];then
     rm -rf ${DLDIR}
  fi;

  if [ ! -d ${1}/run/lock ];then
    mkdir -p ${1}/run/lock
  fi;

  echo "Install packages"
  dnf ${DNF_OPT} install packagegroup-comb-dunfell
  dnf ${DNF_OPT} --noautoremove erase packagegroup-comb-dunfell alsa-state
  dnf ${DNF_OPT} install alsa-state
  dnf ${DNF_OPT} reinstall adwaita-icon-theme*
  dnf ${DNF_OPT} mark install ${MARK_PKG}

  post_install ${1}
}

cleanup_img(){
  umount ${2}/boot ${2}

  if [ "${1}" ] && [ -b ${1} ];then
    if losetup -d ${1};then
      rm -f ${1}p?
    fi;
  fi;
}

unpack_ns_img() {
  if [ -e ${1}.img.pack ] && [ -e ${1}.img.pack.xz ] && [ ${1}.img.pack.xz -nt ${1}.img.pack ];then
    rm ${1}.img.pack
    xz -d -k --verbose ${1}.img.pack.xz || return 1
   elif [ ! -e ${1}.img.pack ] && [ -e ${1}.img.pack.xz ] && [ ${1}.img.pack.xz -nt ${1}.img.pack ];then
    xz -d -k --verbose ${1}.img.pack.xz || return 1
   elif [ ! -e ${1}.img.pack ];then
    return 1
  fi

  dd status=progress if=/dev/zero of=${1}.img bs=1M count=1536

  LOOP=$(losetup -f -P --show ${1}.img)

  parted -s ${LOOP} mklabel msdos mkpart primary fat32 1M 100M mkpart primary ext4 100M 100%

  mkfs.vfat ${LOOP}p1 -n BOOT
  dd conv=notrunc,nocreat if=${1}.img.pack status=progress bs=1M skip=1 count=94 of=${LOOP}p1

  mkfs.ext4 ${LOOP}p2 -L ROOT
  e2image -pra -o 99614720 ${1}.img.pack ${LOOP}p2

  echo "Checking File System"
  fsck.fat -a ${LOOP}p1
  e2fsck -C 0 -fy ${LOOP}p2
  echo "Expanding File System"
  resize2fs ${LOOP}p2
  losetup -d ${LOOP}

  if [ ! -d ${1} ];then
    mkdir ${1}
  fi;
  return 0
}

create_ns_image() {
  if [ ! -d ${1} ];then
    mkdir ${1}
  fi;

  dd status=progress if=/dev/zero of=${1}.img bs=1M count=1536
  parted -s ${1}.img mklabel msdos mkpart primary fat32 1M 100M mkpart primary ext4 100M 100%

  LOOP=$(losetup -P -f --show ${1}.img)
  if [ ! "${LOOP}" ];then
    echo "Could not allocate loop device"
    rm -rf ${1} ${1}.img
    return 1
  fi;

  mkfs.vfat ${LOOP}p1 -n BOOT
  mkfs.ext4 ${LOOP}p2 -L ROOT

  if ! mount ${LOOP}p2 ${1};then
    losetup -d ${LOOP}
    rm -rf ${1} ${1}.img
  fi;

  mkdir ${1}/boot
  if ! mount ${LOOP}p1 ${1}/boot;then
    umount ${1}
    losetup -d ${LOOP}
    rm -rf ${1} ${1}.img
  fi;

  tar -C ${1} -xf ${1}.tar.bz2

  umount ${1}/boot ${1}
  losetup -d ${LOOP}
}

pack_ns_img() {
  if ! check_ns_img ${1};then
    echo "Image not found"
    return 1;
  fi;

  if [ -e ${1}.img.pack ] && [ ${1}.img.pack -nt ${1}.img ];then
    echo "Already packed"
    return 0;
  fi;

  if [ -e ${1}.img.pack ];then
    rm ${1}.img.pack
  fi;

  LOOP=$(losetup -f -P --show ${1}.img)
  fsck.fat -a ${LOOP}p1
  e2fsck -C 0 -fy ${LOOP}p2
  resize2fs -p -M ${LOOP}p2
  e2fsck -C 0 -fy ${LOOP}p2
  resize2fs -p -M ${LOOP}p2
  e2fsck -C 0 -fy ${LOOP}p2
  resize2fs -p -M ${LOOP}p2
  e2image -pra -O 99614720 ${LOOP}p2 ${1}.img.pack
  resize2fs -p ${LOOP}p2
  losetup -d ${LOOP}

  dd status=progress conv=nocreat,notrunc if=${1}.img bs=1M count=95 of=${1}.img.pack
  dd status=progress conv=nocreat,notrunc oflag=append if=/dev/zero bs=1M count=1 of=${1}.img.pack
  LOOP=$(losetup -f -P --show ${1}.img.pack)

  parted -s ${LOOP} mklabel msdos mkpart primary fat32 1M 100M mkpart primary ext4 100M 100%
  fsck.fat -a ${LOOP}p1
  e2fsck -C 0 -fy ${LOOP}p2
  resize2fs -p ${LOOP}p2

  losetup -d ${LOOP}
}

xz_pack_ns_img() {
  if [ ! "${1}" ] || [ ! -e ${1}.img.pack ];then
    echo "Image not found"
    return 1;
  fi;

  if [ -e ${1}.img.pack.xz ] && [ ${1}.img.pack.xz -nt ${1}.img.pack ];then
    echo "Already compressed"
    return 0;
  fi;

  if [ ! -e ${1}.img.pack.xz ] || [ ${1}.img.pack -nt ${1}.img.pack.xz ];then
    if [ -e ${1}.img.pack.xz ];then
      rm ${1}.img.pack.xz
    fi;
    xz -T 0 -k --verbose ${1}.img.pack
    touch ${1}.img.pack.xz
  fi;
}


check_ns_img() {
  if [ ! "${1}" ];then
     return 1
   elif [ -e "${1}.img" ];then
     return 0
   elif [ ! -e ${1}.img.pack ] && [ ! -e ${1}.img.pack.xz ];then
     return 1
  fi;

  unpack_ns_img ${1} || exit 1
}

install_root(){
  DNF_OPT="-y -q --installroot=${1}"

  if ! check_ns_img ${1};then
    dd status=progress if=/dev/zero of=${1}.img bs=1M count=1536
  fi;

  if [ -e ${1}.img ];then
    BLKDEV=$(losetup --show -P -f ${1}.img)
   else
    echo "Imgage file not found"
    exit
  fi;

  if [ ! "${BLKDEV}" ];then
    echo "Image file not loaded"
    exit;
  fi;

  if [ -b ${BLKDEV} ] && [ ! -b ${BLKDEV}p2 ];then
    parted -s ${BLKDEV} mklabel msdos mkpart primary fat32 1M 100M mkpart primary ext4 100M 100%
    mkfs.vfat ${BLKDEV}p1 -n BOOT
    mkfs.ext4 ${BLKDEV}p2 -L ROOT
  fi;

  if [ ! -d ${1} ];then
    mkdir -p ${1}
  fi;

  if [ ! -b ${BLKDEV}p5 ];then
    ROOT_PART=${BLKDEV}p2
    BOOT_PART=${BLKDEV}p1
   else
    ROOT_PART=${BLKDEV}p5
    BOOT_PART=${BLKDEV}p4
  fi

  if mount ${ROOT_PART} ${1};then
    if [ ! -d ${1}/boot ];then
      mkdir -p ${1}/boot
    fi;
    if ! mount ${BOOT_PART} ${1}/boot;then
       echo "Image file boot not mounted"
       cleanup_img ${BLKDEV} ${1}
       exit
    fi;
   else
     echo "Image file not mounted"
     cleanup_img ${BLKDEV} ${1}
     exit
  fi;

  if [ ! -e ${1}/etc/dnf/dnf.conf ];then
    echo "Add RPM/DNF files to new root"
    rsync -aR /etc/rpmrc /etc/rpm /etc/dnf /etc/yum.repos.d ${1}/
  fi;

  mount_sys ${1}

  if [ ! -d ${1}/bin ];then
    mkroot_base ${1}
   else
    if ! dnf ${DNF_OPT} --installed list packagegroup-comb-dunfell > /dev/null 2>&1;then
      dnf ${DNF_OPT} install packagegroup-comb-dunfell
      dnf ${DNF_OPT} reinstall alsa-state adwaita-icon-theme*
      dnf_update ${1}
      post_install ${1}
     else
      dnf_update ${1}
    fi;
  fi;

  for sysdir in dev/pts dev proc sys var/volatile/ run;do
      umount ${1}/${sysdir}
  done;

  dnf ${DNF_OPT} clean all

  if [ -e ${1}/etc/volatile.cache ];then
      rm  ${1}/etc/volatile.cache
  fi;

  dnf ${DNF_OPT} --installed list |awk '{printf "%s\n",$1}' |sort > list.newroot
  dnf -q --installed list |awk '{printf "%s\n",$1}' |sort > list

  cleanup_img ${BLKDEV} ${1}
}

mount_image() {
  if [ -e ${TMPDEV} ];then
    echo "Already mounted"
    exit 1
  fi;

  if ! check_ns_img ${1};then
    echo "Image missing"
  fi;

  if [ ! -d ${1} ];then
    echo "Directory missing"
    exit 1
  fi;

  LOOP=$(losetup -f)
  ln -s ${LOOP} ${TMPDEV}

  losetup -P ${LOOP} ${1}.img
  if [ ! -b ${LOOP}p5 ];then
    mount ${LOOP}p2 ${1}
    mount ${LOOP}p1 ${1}/boot
   else
    mount ${LOOP}p5 ${1}
    mount ${LOOP}p4 ${1}/boot
  fi
  mount_sys ${1}
}

umount_image(){
  if [ ! -e ${TMPDEV} ];then
    echo "Not mounted"
    exit 1
  fi;

  if [ ! -d ${1} ];then
    echo "Directory missing"
    exit 1
  fi;

  for sysdir in /dev/pts /dev /proc /sys /var/volatile /boot /run /;do
    umount  ${1}${sysdir}
  done;

  losetup -d ${TMPDEV}
  rm ${TMPDEV}
}

diff_image() {
  if [ ! -e ${TMPDEV} ];then
    echo "Not mounted"
    exit 1
  fi;

  if [ ! -d ${1} ];then
    echo "Directory missing"
    exit 1
  fi;

  diff -x home -x dev -x sys -x proc -x var -x run -x mnt -x legato -x data -x etc -x tmp -qr ${1} / |grep -v __pycache__
  diff -x passwd -x shadow -x group -x gshadow -x ld.so.cache -x ca-certificates.crt -x group- -x shadow- -x passwd- -x .pwd.lock \
       -x gshadow- -x default -x ssh -x timestamp -x *.lock~~XXXXXX -ur ${1}/etc /etc/
}

fix_duoplicates() {
  DLDIR=$(mktemp -d -p ~ rpmdl-XXXXXXXXX)

  if [ ! "${DLDIR}" ] || [ ! -d ${DLDIR} ];then
    return 1
  fi;

  #Handle kernel Modules
  if dnf ${DNF_OPT}  remove --duplicates --downloadonly --destdir=${DLDIR} kernel-module*;then
    rpm --nodeps --root=${1}/ --noscripts --force -U ${DLDIR}/*.rpm && rm ${DLDIR}/*.rpm
    if dnf ${DNF_OPT}  remove --duplicates --downloadonly --destdir=${DLDIR} kernel-module*;then
      rpm --nodeps --root=${1}/ --noscripts --force -i --reinstall  ${DLDIR}/*.rpm && rm ${DLDIR}/*.rpm
    fi;
    kern_depmod ${1}
  fi;
  rm ${DLDIR}/*.rpm

  #Handle kernel
  if dnf ${DNF_OPT}  remove --duplicates --downloadonly --destdir=${DLDIR} ${KERNEL_PKG};then
    rpm --nodeps --root=${1}/ --noscripts --force -U ${DLDIR}/*.rpm && rm ${DLDIR}/*.rpm
    if dnf ${DNF_OPT}  remove --duplicates --downloadonly --destdir=${DLDIR} ${KERNEL_PKG};then
      rpm --nodeps --root=${1}/ --noscripts --force -i --reinstall  ${DLDIR}/*.rpm && rm ${DLDIR}/*.rpm
    fi;
  fi;
  rm ${DLDIR}/*.rpm

  #Handle non legato apps
  if dnf ${DNF_OPT}  remove --duplicates --downloadonly --exclude=packagegroup-comb-legato --exclude=legato --destdir=${DLDIR};then
    rpm --nodeps --root=${1}/ --force --replacefiles --replacepkgs -U ${DLDIR}/*.rpm && rm ${DLDIR}/*.rpm
    if dnf ${DNF_OPT}  remove --duplicates --downloadonly --exclude=packagegroup-comb-legato --exclude=legato --destdir=${DLDIR};then
      rpm --nodeps --root=${1}/ --force -i --reinstall  ${DLDIR}/*.rpm && rm ${DLDIR}/*.rpm
    fi;
  fi;

  #Fixup LEgato
  if dnf ${DNF_OPT}  remove --duplicates --downloadonly --destdir=${DLDIR} packagegroup-comb-legato legato;then
    rpm --nodeps --root=${1}/ --force --replacefiles --replacepkgs -U ${DLDIR}/*.rpm && rm ${DLDIR}/*.rpm
    if dnf ${DNF_OPT}  remove --duplicates --downloadonly --destdir=${DLDIR} packagegroup-comb-legato legato;then
      rpm --nodeps --root=${1}/ --force -i --reinstall  ${DLDIR}/*.rpm && rm ${DLDIR}/*.rpm
    fi;
  fi;

  rm -rf ${DLDIR}
}

reinstall_pkg() {
  echo "Reinstall Packages"
  dnf ${DNF_OPT} --exclude kernel* --exclude legato --exclude util-linux* --exclude procps --exclude coreutils --exclude ca-certificates --exclude lsb-release --exclude sysvinit* --exclude shadow* reinstall '*' || return 1
}

reinstall_cacerts() {
  DLDIR=$(mktemp -d -p /tmp rpmdl-XXXXXXXXX)
  if [ ! "${DLDIR}" ] || [ ! -d ${DLDIR} ];then
    return 1
  fi;

  echo "Reinstall CA Certs"
  (dnf ${DNF_OPT} --downloadonly --destdir=${DLDIR} reinstall ca-certificates && \
	rm -rf ${1}/etc/ssl/certs/* && rpm --root=${1}/ --quiet -i --reinstall ${DLDIR}/ca-certificates* && \
	sed -i '/^$/d' ${1}/usr/lib/ssl-1.1/certs/ca-certificates.crt) || (rm -rf ${DLDIR};return 1)

  rm -rf ${DLDIR}
}

reinstall_clean() {
  echo "Erase Unused"
  dnf ${DNF_OPT} --noautoremove erase pulseaudio-module-detect pulseaudio-module-udev-detect util-linux-raw libsrtp2-2 kernel-cmdline.${ARCH} perl-module-unicode-collate-locale*
  rpm --root=${1}/ --noscripts -e `dnf --installed list kernel*5.4.72-v8 |grep -E "^kernel.*\-5.4.72-v8" |awk '{print $1}' `
  rm -rf ${1}/lib/modules/5.4.72-v8/
}

reinstall_alt() {
  echo "Reinstall Alt Packages"
  dnf ${DNF_OPT} reinstall util-linux-mountpoint util-linux-nologin || return 1
  for alt in procps sysvinit;do
    dnf ${DNF_OPT} reinstall ${alt}* || return 1
  done
  dnf ${DNF_OPT} --exclude util-linux-mountpoint --exclude util-linux-nologin reinstall util-linux* || return 1
  for alt in shadow coreutils;do
    dnf ${DNF_OPT} reinstall ${alt}* || return 1
  done
}

reinstall_kern() {
  DLDIR=$(mktemp -d -p ~ rpmdl-XXXXXXXXX)
  if [ ! "${DLDIR}" ] || [ ! -d ${DLDIR} ];then
    return 1
  fi;

  echo "Reinstall Kernel"
  if [ -d ${1}/lib/modules/${KERN_VER} ];then
    dnf ${DNF_OPT} --downloadonly --destdir=${DLDIR} reinstall kernel-module*${KERN_VER} kernel-modules || (rm -rf ${DLDIR};return 1)
   else
    dnf ${DNF_OPT} --downloadonly --destdir=${DLDIR} reinstall kernel-module* kernel-modules
  fi;
  rpm --root=${1}/ --nodeps --noscripts -i --reinstall ${DLDIR}/kernel-module* && rm ${DLDIR}/kernel-module*
  kern_depmod ${1}
  rm -rf ${DLDIR}

  dnf ${DNF_OPT} --exclude kernel-module* reinstall kernel*
}

full_reinstall() {
  #reset locale-achive and timetamp
  rm ${WKDIR}/etc/timestamp ${WKDIR}/usr/lib/locale/locale-archive

  #rund update and check
  check_install ${WKDIR}

  #clean
  reinstall_clean ${1}

  #Reinstall all non alt/kernel packages
  reinstall_pkg

  #Reinstall alt packages
  reinstall_alt ${1}

  #Reinstall SSL CERTS
  reinstall_cacerts ${1}

  #Reinstall kernel
  reinstall_kern ${1}

  echo "Reinstall App/LSB"
  dnf ${DNF_OPT} reinstall legato lsb-release

  /sbin/ldconfig
}


check_install() {
  if [ -e ${1}/boot/dt-blob.bin ];then
     KERNEL_PKG="${KERNEL_PKG} ${KERNEL_PKG_RASPI}";
  fi;

  echo "Rebuild  DB"
  (rpm --root=${1}/ --rebuilddb && dnf ${DNF_OPT} clean all && dnf ${DNF_OPT} repolist >/dev/null 2>&1) || return 1

  dnf_update ${1}/

  #Fix LIBC
  #rpm -e --justdb --nodeps ldd
  LDD_VER=$(dnf info ldd |awk '/Version/ {printf "%s",$3}')
  LIBC_VER=$(dnf info libc6 |awk '/Version/ {printf "%s",$3}')
  if [ "${LDD_VER}" != "${LIBC_VER}" ];then
    echo "Libc version out of date"
    dnf ${DNF_OPT} --allowerasing install libc6-${LDD_VER} ldconfig-${LDD_VER} libc6-utils-${LDD_VER}
    dnf ${DNF_OPT} reinstall dnf perl-module-config-heavy iptables-module-ip6t-eui64 iptables-module-xt-trace usb-modeswitch-data lsb-release base-files
    dnf ${DNF_OPT} install openssh-sftp-server
  fi;

  if ! dnf ${DNF_OPT} check --duplicates;then
    echo "Duplicates Found"
    fix_duoplicates ${1}
    kern_update ${1}
    dnf ${DNF_OPT} upgrade -b
    if ! dnf ${DNF_OPT} check --duplicates;then
     fix_duoplicates ${1}
     dnf ${DNF_OPT} upgrade -b
     if ! dnf ${DNF_OPT} check --duplicates;then
        fix_duoplicates ${1}
        dnf ${DNF_OPT} upgrade -b
      fi;
    fi;
  fi;

  #Fixup dependancies
  (dnf ${DNF_OPT} --allowerasing reinstall `dnf check |awk '/has missing requires/ {printf "%s ",$1}'` |awk -v RPM_DIR="--root=${1}/" '/not available/ {printf " rpm %s -e --justdb --nodeps %s\n",RPM_DIR,$3}' |sh) >/dev/null 2>&1
  (dnf ${DNF_OPT} --allowerasing reinstall `dnf check |awk '/has missing requires/ {printf "%s ",$1}'` |awk -v RPM_DIR="--root=${1}/" '/not available/ {printf " rpm %s -e --justdb --nodeps %s\n",RPM_DIR,$3}' |sh) >/dev/null 2>&1

  echo "Remove Package Groups/Update"
  dnf ${DNF_OPT} upgrade -b
  dnf ${DNF_OPT} --noautoremove erase packagegroup*
  dnf_update ${1}/

  echo "Reinstall Package Groups"
  (dnf ${DNF_OPT} install packagegroup-comb-dunfell && dnf ${DNF_OPT} --noautoremove erase packagegroup-comb-dunfell) || return 1
  dnf ${DNF_OPT} mark install ${MARK_PKG}

  /sbin/ldconfig
}

chroot_img() {
  cp /etc/resolv.conf ${1}/run/resolvconf
  if [ ! -e  ${1}/etc/resolv.conf ];then
    ln -s /etc/resolvconf/run/resolv.conf ${1}/etc/resolv.conf
  fi;
  if [ ! -d ${1}/mnt/legato ];then
    mkdir -p ${1}/mnt/legato
  fi;
  env -i TERM=${TERM} HOME=/home/root LANG=${LANG} /usr/sbin/chroot ${1} /bin/bash -l
}

usage_help() {
cat <<__EOF_HELP__

$(basename ${0}) [OPTION [PATH]] | [PATH]

With no options supplied the system is updated should there be a duplicate file or dependancy is not met --fix will be executed.

if a path is supplied the image at that path will be updated if a image does not exist it will be created..

Help
----

-? | -h | --help
	Display this help information.
	Press q to quit.
	Press h to see more info on options.

Image files
-----------

<file>.img
	Created with --import
	Created with <file> as path
	Created with --unpack

<file>.img.xz
	Compressed full image.
	created with --xz option

<file>.img.pack
	Packed image where the size is reduced to flash onto a system
	a image file can be generated from this file by importing it using --import option.
	created with --pack option

<file>.img.pack.xz
	Compressed packed image used that can be copied to a production system for flashing
	a image file can be generated from this file by importing it using --import option.
	created with --xz-pack option.

<file>.tar.bz2
	Compresed tar file downloweded from the repository.
	created with --import option

Path
----

The path is the path to the mount point where the file  <path>/<mount>.img is mounted the full path must be given.
The default path <${DEF_IMG}> is specified using - as a path value.

Example (<PATH> = -)
path ${DEF_IMG} where file ${DEF_IMG}.img will be mounted.

If a path is specified and no image exists one will be created from the reposiory see the --import option.

Update Options
--------------

It is best to use --chroot to execute these functions on a path if no path is supplied / is used.
If a path is supplied the image will be mounted and unmounted if not mounted.

--fix [path]
	Rebuild the rpm db incase its inconsistent.
	Update the system.
	Ensure the correct version of libc is installed.
	Resolve any duplicates.
	Resolve any missing dependancies.
	Reinstall all packagegroups to ensure any missing packages are installed.
	If the locale-archive config.txt cmdline.txt timestamp are missing they created

--reinstall [path]
	Remove locale-archive and timestamp to be recreated when --fix is executed below.
	Execute --fix see above
	Remove packages no longer used can be executed using --cleanup
	Reinstall all packages except for kernel, cacerts, app ,lsb_release and packages to keep alternates in sync
	Reinstall all packages neede4d to keep alternates in sync can be executed using --alt
	Reinstall ca certificates can be executed using --cacerts
	Reinstall kernel can be executed using --kern
	Reinstall lsb_release and app

--cleanup [path]
	Remove pulseaudio auto detect along with packages been obsoleted

--alt [path]
	Reinstall packages with alternates in the correct order to match those generated by build system.
	If --diff outputs alternate files executing this will re sync them.

--cacerts [path]
	Update mozilla cacerts without using dnf as dnf requires cacerts.

--kern [path]
	Reinstall the currently installed kernel without using dnf to install the packages to speed up the install.

--mk-locale [path]
	Update the locale archive if needed see output of --diff

File Options
------------

If no path is supplied - is used these functions apply to image files that should be un mounted first.

--xz [path]
	Create a compressed image file if no path is supplied - is used.

--pack [path]
	Create a packed image to flash a new system.

--xz-pack [path]
	Create a compressed pack file it will update or create the pack file before compressing (--pack).

--unpack [path]
	Create a image from a packed image or compressed pack image.

--import [path]
	Create a image file from a compressed tar file down loaded from repository.

Image Options
-------------

If no path is supplied - is used these functions apply to image files that should be un mounted first.
The image will be mounted and unmounted if not mounted running except for --mount / --umount.

--mount [path]
	Mount image this is not required unless you want to run multiple commands without unmounting.
	Do not execute --mount when executing file options.
	If a packed file is found and no image exists it is unpacked see --unpack.
	The image must be unmounted with --umount.

--umount [path]
	Unmount a image mounted with --mount

--chroot [path]
	Chroot into a mounted image this is the prefered way to execute update commands on a image.

--diff [path]
	Compare the system to mounted filesystem.

__EOF_HELP__

rpm --quiet -q wpnetlink && cat <<__EOF_HELP__

Production tools (wpnetlik)
---------------------------

The path used is hardcoded to ~/comb-ns:\${FW_PATH}/raspi-cm4-64/comb-ns
The above path is the same as $(basename ${0}) default path.

To start/stop the wpnetlink service.

/etc/init.d/wpnetlink <start | stop>

mount_ns.sh
-----------

If no options are specified it will execute --mount or --unmount depending on if image is mounted.
These tools are designed to be run on non native systems ie standard pi or linux pc its best to use $(basename $0).

--mount
	Similar to --mount above does not require a path.
	If a packed file is found and no image exists it is unpacked see --unpack.

--rpiboot
	Similar to --mount but mount a system initiated with rpiboot ensure wpnetlink is stopped before using this option.


--umount
	Similar to --umount above does not require a path.

--xz
	Create a compressed image file.

--pack
	Create a packed image to flash a new system..

--xz-pack
	Create a compressed pack file it will update or create the pack file before compressing (--pack).

--import
	Create a image file from a compressed tar file down loaded from repository.

--chroot
	Chroot into a mounted image this is the prefered way to execute update commands on a image.
	This requires it to be run on native CPU ie PI 3/4

flash_ns.sh
-----------

This runs the flash subroutine from the command line this should not be done unless wpnetlink is stoped or the module is blocked.
A module will not be flashed twice in a row running this command even when wpnetlink is running will force it is flashed.
If you run it while wpnetlink is active its recommended to quit it before swaping modules.

dnf_lan.sh <ip[:port]> / dnf_remote.sh <remote ssh port>
--------------------------------------------------------

Execute dnf commands on a remote systems to run ${0} --fix via atd this is is needed on older boards or if the script fails.

To set the SSH_KEY variable execute:
export SSH_KEY=<path to key file>

__EOF_HELP__
}

if [ "${2}" ] && [ "${2}" != "-" ];then
  IMG=${2-${DEF_IMG}}
 else
  IMG=${DEF_IMG}
fi

if [ "${1}" == "--help" ] || [ "${1}" == "-h" ] || [ "${1}" == "-?" ];then
  usage_help |less
  exit 0
 elif [ "${1}" == "--mount" ];then
  shift;
  mount_image ${IMG}
  exit 0;
 elif [ "${1}" == "--umount" ];then
  shift;
  umount_image ${IMG}
  exit 0;
 elif [ "${1}" == "--chroot" ];then
  shift;
  if [ ! -e ${TMPDEV} ];then
    mount_image ${IMG}
    chroot_img ${IMG}
    umount_image ${IMG}
   else
    chroot_img ${IMG}
  fi;
  exit 0;
 elif [ "${1}" == "--unpack" ];then
  shift;
  unpack_ns_img ${IMG} || exit 1
  exit 0
 elif [ "${1}" == "--pack" ];then
  shift;
  pack_ns_img ${IMG} || exit 1
  exit 0
 elif [ "${1}" == "--xz-pack" ];then
  shift;
  pack_ns_img ${IMG} || exit 1
  xz_pack_ns_img ${IMG} || exit 1
  exit 0
 elif [ "${1}" == "--import" ];then
  shift;
  if check_ns_img ${IMG};then
    echo "Image exits"
    exit 1
  fi;
  wget ${BASEURL}/${ARCH_NAME}/${CODENAME}/img/core-image-comb-${ARCH_NAME}.tar.bz2 -O ${IMG}.tar.bz2
  create_ns_image ${IMG}
  exit 0
 elif [ "${1}" == "--diff" ];then
  shift;
  if [ ! -e ${TMPDEV} ];then
    mount_image ${IMG}
    diff_image ${IMG}
    umount_image ${IMG}
   else
    diff_image ${IMG}
  fi;
  exit 0
 elif [ "${1}" == "--fix" ];then
  shift;
  if [ "${1}" ] && [ -d ${IMG} ];then
    DNF_OPT="-y -q --installroot=${IMG}"
    WKDIR="${IMG}"
    if [ ! -e ${TMPDEV} ];then
      mount_image ${IMG}
      UMT_FLAG=1
    fi;
  else
    DNF_OPT="-y -q"
    WKDIR=""
  fi;
  check_install ${WKDIR}
  if [ "${UMT_FLAG}" == "1" ] && [ -e ${TMPDEV} ];then
    umount_image ${IMG}
  fi
  if [ ! "${WKDIR}" ] && [ -e /run/initctl ];then
    /sbin/reboot
  fi
  exit 0;
 elif [ "${1}" == "--reinstall" ];then
  shift;
  if [ "${1}" ] && [ -d ${IMG} ];then
    DNF_OPT="-y -q --installroot=${IMG}"
    WKDIR="${IMG}"
    if [ ! -e ${TMPDEV} ];then
      mount_image ${IMG}
      UMT_FLAG=1
    fi;
  else
    DNF_OPT="-y -q"
    WKDIR=""
  fi;
  full_reinstall ${WKDIR}
  if [ "${UMT_FLAG}" == "1" ] && [ -e ${TMPDEV} ];then
    umount_image ${IMG}
  fi
  if [ ! "${WKDIR}" ] && [ -e /run/initctl ];then
    /sbin/reboot
  fi
  exit 0;
 elif [ "${1}" == "--cleanup" ];then
  shift;
  if [ "${1}" ] && [ -d ${IMG} ];then
    DNF_OPT="-y -q --installroot=${IMG}"
    WKDIR="${IMG}"
    if [ ! -e ${TMPDEV} ];then
      mount_image ${IMG}
      UMT_FLAG=1
    fi;
  else
    DNF_OPT="-y -q"
    WKDIR=""
  fi;
  reinstall_clean ${wkdir} || exit 1
  if [ "${UMT_FLAG}" == "1" ] && [ -e ${TMPDEV} ];then
    umount_image ${IMG}
  fi
  exit 0
 elif [ "${1}" == "--cacerts" ];then
  shift;
  if [ "${1}" ] && [ -d ${IMG} ];then
    DNF_OPT="-y -q --installroot=${IMG}"
    WKDIR="${IMG}"
    if [ ! -e ${TMPDEV} ];then
      mount_image ${IMG}
      UMT_FLAG=1
    fi;
  else
    DNF_OPT="-y -q"
    WKDIR=""
  fi;
  reinstall_cacerts ${wkdir} || exit 1
  if [ "${UMT_FLAG}" == "1" ] && [ -e ${TMPDEV} ];then
    umount_image ${IMG}
  fi
  exit 0
 elif [ "${1}" == "--alt" ];then
  shift;
  if [ "${1}" ] && [ -d ${IMG} ];then
    DNF_OPT="-y -q --installroot=${IMG}"
    WKDIR="${IMG}"
    if [ ! -e ${TMPDEV} ];then
      mount_image ${IMG}
      UMT_FLAG=1
    fi;
  else
    DNF_OPT="-y -q"
    WKDIR=""
  fi;
  reinstall_alt ${wkdir} || exit 1
  if [ "${UMT_FLAG}" == "1" ] && [ -e ${TMPDEV} ];then
    umount_image ${IMG}
  fi
  exit 0
 elif [ "${1}" == "--kern" ];then
  shift;
  if [ "${1}" ] && [ -d ${IMG} ];then
    DNF_OPT="-y -q --installroot=${IMG}"
    WKDIR="${IMG}"
    if [ ! -e ${TMPDEV} ];then
      mount_image ${IMG}
      UMT_FLAG=1
    fi;
  else
    DNF_OPT="-y -q"
    WKDIR=""
  fi;
  reinstall_kern ${WKDIR} || exit 1
  if [ "${UMT_FLAG}" == "1" ] && [ -e ${TMPDEV} ];then
    umount_image ${IMG}
  fi
  exit 0
 elif [ "${1}" == "--mk-locale" ];then
  shift;
  if [ "${1}" ] && [ -d ${IMG} ];then
    WKDIR="${IMG}"
    if [ ! -e ${TMPDEV} ];then
      mount_image ${IMG}
      UMT_FLAG=1
    fi;
   else
    WKDIR=""
  fi;
  rm ${WKDIR}/usr/lib/locale/locale-archive
  mk_locale ${WKDIR}
  if [ "${UMT_FLAG}" == "1" ] && [ -e ${TMPDEV} ];then
    umount_image ${IMG}
  fi
  exit 0
 elif [ "${1}" == "--xz" ];then
  shift;
  if [ -e ${IMG}.img ];then
    if [ -e "${IMG}.img.xz" ];then
      rm ${IMG}.img.xz
    fi;
    xz -T 0 -k --verbose ${IMG}.img
  fi;
  exit 0
fi;

if [ "${1}" ];then
  if [ "${1}" == "-" ];then
    IMG=${DEF_IMG}
   elif [ "${1:0:1}" ==  "-" ];then
    echo "Not creating image ${1}"
    exit 0;
  fi
  KERNEL_PKG="${KERNEL_PKG} ${KERNEL_PKG_RASPI}";
  install_root ${1}
 elif ! dnf check;then
  DNF_OPT="-y -q"
  check_install
  if [ -e /run/initctl ];then
    /sbin/reboot
  fi
  exit 0;
 else
  DNF_OPT="-y -q"
  if [ -e /boot/dt-blob.bin ];then
    KERNEL_PKG="${KERNEL_PKG} ${KERNEL_PKG_RASPI}";
  fi;
  dnf_update
fi;
