#!/bin/bash

#Fixup on buildroot
#Only in newroot/etc/dnf: aliases.d

#Only in root/etc/default: postinst
#Only in root/etc/: rpm-postinsts
#Only in root/etc/: timestamp
#Only in root/etc/: version

ulimit -s unlimited

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 bootfiles kernel-devicetree kernel-modules kernel-module-* kernel-image-*"

ARCH=$(cut -d- -f1 /etc/rpm/platform)
CODENAME=$(lsb_release -c |cut -f2)
ARCH_NAME=$(echo ${ARCH} |tr '_' '-')
REPO="oe-remote-repo"

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=https://honeycomb.comb-communications.com/${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
    if [ ! -e ${1}/lib/modules/${kver}/modules.dep.bin ];then
      depmod -b ${1}/ -a ${kver}
    fi;
  done
}

kern_quick_install(){
  dnf ${DNF_OPT} --destdir=${1} --downloadonly install ${KERNEL_PKG}
  if rpm --root=${2}/ --replacefiles --noscripts -i ${1}/*.rpm 2>/dev/null;then
    kern_depmod ${2}
    rm ${1}/*.rpm
    return 0
  fi;
}

kern_quick_update(){
  dnf ${DNF_OPT} --destdir=${1} --downloadonly update ${KERNEL_PKG}
  if rpm --root=${2}/ --replacefiles --noscripts --replacefiles --replacepkgs -U ${1}/kernel*.rpm ${1}/*.rpm 2>/dev/null;then
    kern_depmod ${2}
    rm ${1}/*.rpm
  fi;
}

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)-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
    rm -rf ${1}/var/volatile/tmp ${1}/var/volatile/log ${1}/run/lock
    sed -i '/^$/d' ${1}/usr/lib/ssl-1.1/certs/ca-certificates.crt
  fi;

  date -u +%4Y%2m%2d%2H%2M%2S  > ${1}/etc/timestamp

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

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
    if [ ! "${1}" ] && [ -e /run/initctl ];then
      echo "Rebooting"
      /sbin/reboot
    fi;
}

dnf_update() {
  echo "Checking DB"
  if ! rpm --verifydb;then
    rpm --rebuilddb;
  fi;

  echo "Checking Install"
  if ! rpm --root=${1}/ -q packagegroup-comb >/dev/null;then
    kern_update ${1}
    dnf  ${DNF_OPT} install packagegroup-comb
    post_install ${1}
    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}
  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 sysvinit procps 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} 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;
}

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

  if [ ! -e "${1}.img" ];then
    dd if=/dev/zero of=${1}.img bs=1M count=1024
  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_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 /dev/newroot ];then
    echo "Already mounted"
    exit 1
  fi;

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

  LOOP=$(losetup -f)
  ln -s ${LOOP} /dev/newroot

  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 /dev/newroot ];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 /dev/newroot
  rm /dev/newroot
}

diff_image() {
  if [ ! -e /dev/newroot ];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/

  exit 0
}

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_PKG};then
    rpm --nodeps --root=${1}/ --noscripts --force -U ${DLDIR}/bootfiles*.rpm ${DLDIR}/kernel*.rpm && rm ${DLDIR}/kernel*.rpm
    if dnf ${DNF_OPT}  remove --duplicates --downloadonly --destdir=${DLDIR} ${KERNEL_PKG};then
      rpm --nodeps --root=${1}/ --noscripts --force -i --reinstall  ${DLDIR}/bootfiles*.rpm ${DLDIR}/kernel*.rpm && rm ${DLDIR}/*.rpm
    fi;
    kern_depmod ${1}
  fi;

  #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}
}

check_install() {
  if [ "${1}" ];then
    DNF_OPT="-y -q --installroot=${1}"
  else
    DNF_OPT="-y -q"
  fi;

  rpm --root=${1}/ --rebuilddb
  dnf ${DNF_OPT} clean all

  dnf_update ${1}/

  if ! dnf ${DNF_OPT} check --duplicates;then
    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;

  dnf ${DNF_OPT} upgrade -b

  dnf ${DNF_OPT} --noautoremove erase packagegroup*

  dnf_update ${1}/

  dnf ${DNF_OPT} install packagegroup-comb-dunfell
  dnf ${DNF_OPT} --noautoremove erase packagegroup-comb-dunfell
  dnf ${DNF_OPT} mark install ${MARK_PKG}

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

if [ "${1}" == "--mount" ];then
  shift;
  mount_image ${1}
  exit 0;
 elif [ "${1}" == "--umount" ];then
  shift;
  umount_image ${1}
  exit 0;
 elif [ "${1}" == "--chroot" ];then
  shift;
  mount_image ${1}
  cp /etc/resolv.conf ${1}/run/resolvconf
  env -i TERM=${TERM} HOME=/home/root LANG=${LANG} /usr/sbin/chroot ${1} /bin/bash -l
  umount_image ${1}
  exit 0;
 elif [ "${1}" == "--diff" ];then
  shift;
  diff_image ${1}
 elif [ "${1}" == "--fix" ];then
  shift;
  check_install ${1}
 elif [ "${1}" == "--checkup" ];then
    shift;
    DNF_OPT="-y -q"
    if ! dnf ${DNF_OPT} --installed list packagegroup-comb-dunfell > /dev/null 2>&1;then
      dnf ${DNF_OPT} install packagegroup-comb-dunfell
      dnf_update /
      post_install /
     else
      dnf_update /
    fi;
    exit 0;
 elif [ "${1}" == "--xz" ];then
  shift;
  if [ -e "${1}.img" ];then
    if [ -e "${1}.img.xz" ];then
      rm ${1}.img.xz
    fi;
    xz -T 0 -k ${1}.img
  fi;
  exit 0
fi;

if [ "${1}" ];then
  install_root ${1}
 elif ! dnf check;then
  check_install
 else
  DNF_OPT="-y -q"
  dnf_update
fi;
