#!/bin/bash
set -e #exit on error

if [[ $1 == "help" ]] || [[ $1 == "-h" ]] || [[ $1 == "--help" ]];then

  echo "usage vtbuild \<kernel version\>"
  echo "available environment variables"
  echo ""
  echo "CUSTOM_PARAMETER=\"\" custom parameters to be appended."
  echo ""
  echo "CUSTOM_ROOT_DEVICE=\"\" specify custom root device."
  echo "CUSTOM_ROOT_PARAMETER=\"\" directly specify root kernel parameter \(has priority over custom root\)."
  echo "example: \"root=LABEL=name\" \"root=UUID=uuid\" \"root=/dev/sdx\""
  echo ""
  echo "NO_FLASH= any value other than empty prevents automatic/forced flashing."
  echo ""
  echo "CUSTOM_PREFIX=\"\" prefix to be added to image name."
  echo "CUSTOM_SUFFIX=\"\" suffix to be added to image name."
  exit

fi

source $(dirname $BASH_SOURCE)/vtcommon

need_root

# choosing a kernel version
get_kver "${1}"

# it is better to regenerate the initramfs every time
if [ ! -f "/boot/initrd.img-${kver}" ]; then
  
  touch /boot/norebuild # prevents initramfs from running vtbuild again

  if [ "$2" == "noinitgen" ]; then
    echo "Sorry but there is no initramfs to use ;-;. Do you want to build one ?"
    need_confirmation
  fi

  echo "initrd.img-${kver} seems to be missing, trying to generate one for you."
  update-initramfs -c -k "${kver}"

  rm -f /boot/norebuild 2> /dev/null
fi

if [ ! -f "/boot/initrd.img-${kver}" ]; then
  echo "Sorry. I was unable to generate an initramfs. TwT"
  exit 1
fi


# fallback to generated/old cmdline
if [[ ! -f /boot/cmdline-custom ]] && [[ ! -f "/boot/cmdline-${kver}" ]]; then

  if [ -f /boot/cmdline ];then
    echo "migrating old cmdline."
    mv /boot/cmdline /boot/cmdline-custom
  
  else
    echo "cmdline seems to be missing."
    echo "Note. I will create one for you."

    # -n prevents echo from adding new line at the end
    echo -n "console=tty1 rootwait ro fsck.fix=yes fsck.repair=yes net.ifnames=0 ipv6.disable=1 quiet splash" > /boot/cmdline-custom
    
    # cbq requires additional cmdline
    if echo "$kver" | grep -q "cbq"; then
      echo "there is cbq"
      echo -n " deferred_probe_timeout=30 clk_ignore_unused=1" >> /boot/cmdline-custom
    fi

  fi
fi

# move to tremporary directory
WORKING_DIR="$(mktemp -d | tr -d '\n')"
cd $WORKING_DIR
echo WORKING_DIR=\"${WORKING_DIR}\"

get_root_parameter(){
  ROOT_DEVICE=$1
  echo "ROOT_DEVICE=$ROOT_DEVICE"

  if [ "$(lsblk -no LABEL ${ROOT_DEVICE})" != "" ];then 
    echo "using Label as root identifier"
    ROOT_PARAMETER="root=LABEL=$(lsblk -d -no LABEL ${ROOT_DEVICE})"
  elif [ "$(lsblk -no UUID ${ROOT_DEVICE})" != "" ];then
    echo "using UUID as root identifier"
    ROOT_PARAMETER="root=UUID=$(lsblk -d -no UUID ${ROOT_DEVICE})"
  else
    echo "WARNING. the script was unable to determine the partition label or uuid of the device."
    echo "Since CUSTOM_ROOT_PARAMETER was not provided"
    echo "the script will default to the device absolute path as root instead which is NOT RELIABLE."

    ROOT_PARAMETER="root=$ROOT_DEVICE"
    sleep 10
  fi
}

# root parameter gen
if [ "${CUSTOM_ROOT_PARAMETER}" != "" ];then
  ROOT_PARAMETER="${CUSTOM_ROOT_PARAMETER}"
elif [ "${CUSTOM_ROOT_DEVICE}" != "" ];then
  get_root_parameter "${CUSTOM_ROOT_DEVICE}"
elif [ "$(findmnt -n -o SOURCE /)" != "" ];then
  get_root_parameter "$(findmnt -n -o SOURCE /)" # /dev/mmcblk1p4 or similar
else
  echo "ERROR. unable to detect the root device."
  echo "This may occur due to an incorrectly set up chroot"
  echo "aborting the build process."

  exit 2
fi


# generating the final cmdline
echo ""
echo -n "${ROOT_PARAMETER} " > cmdline;

if [ -f /boot/cmdline-${kver} ];then
  echo -n "$(cat /boot/cmdline-${kver}) " >> cmdline;
fi

if [ -f /boot/cmdline-custom ];then
  echo -n "$(cat /boot/cmdline-custom) " >> cmdline;
fi

# custom parameter
if [ "${CUSTOM_PARAMETER}" != "" ];then
  echo -n " ${CUSTOM_PARAMETER}" >> cmdline
fi

# kernel hash
KERNEL_HASH="$(hash_file cmdline)$(hash_file /boot/initrd.img-${kver})"

echo -n " KERNEL_HASH=${KERNEL_HASH}" >> cmdline

echo -n "cmdline used : "
cat cmdline

echo ""
# check out the cmdline
sleep 5

# generating required files
if [ -f "/boot/vmlinux.kpart-initrd-${kver}" ] && [ "${CUSTOM_PREFIX}${CUSTOM_SUFFIX}" == "" ]; then # if it isn't present the command will throw an out of memory error
  cp -v "/boot/vmlinux.kpart-initrd-${kver}" "/boot/vmlinux.kpart-initrd-${kver}.old" 2> /dev/null || out_of_memory
fi
cp "/boot/Image-${kver}" Image || out_of_memory
lzma -9 -z -f -k -v Image || out_of_memory
cp "/boot/initrd.img-${kver}" initrd.img.xz || out_of_memory

# moved cmdline to separate file to make it cleaner to edit
# for cbq add: deferred_probe_timeout=30 clk_ignore_unused=1
# echo "console=tty1 root=LABEL=rootemmc rootwait ro fsck.fix=yes fsck.repair=yes net.ifnames=0 quiet splash" > cmdline

dd if=/dev/zero of=bootloader.bin bs=512 count=1 || out_of_memory

# adjust to dtb names here:
# - cbg: dtb-${kver}/rk3399-gru-*.dtb
# - mt7: dtb-${kver}/mt8173-*.dtb
# - mt8: dtb-${kver}/mt8183-*.dtb
# - cbq: dtb-${kver}/sc7180-trogdor-*.dtb
# - generic: dtb-${kver}/*.dtb
# Note. if you have this script installed, instead of modifying
# it here, you can specify dtbs for your system inside /boot/dtbs (file, not folder) 
# like "sc7180-trogdor-*.dtb" or "sc7180-trogdor-r1.dtb"
# BTW. each dtb seems to add, more or less, 0.09 MiB
# all available dtbs are located at /boot/dtb-<version>
# you can try to deduce the dtb files for your system by running "vthelp dtbs"

echo i

if [ -f "/etc/velvettools/dtbs" ]; then
  dtbs_file="/etc/velvettools/dtbs"
elif [ -f "/boot/dtbs" ]; then
  dtbs_file="/boot/dtbs"
fi

if [ "$dtbs_file" != "" ] && [ "$(cat $dtbs_file)" == "" ]; then
  dtbs_file=""
fi

if [ "$dtbs_file" == "" ]; then
  ls /boot/dtb-${kver}/*.dtb | xargs printf " -b %s" | xargs mkimage -D "-I dts -O dtb -p 2048" -f auto -A arm64 -O linux -T kernel -C lzma -a 0 -d Image.lzma -i initrd.img.xz kernel.itb || out_of_memory
else
  echo "going with $dtbs_file"
  echo "the dtbs picked :"

  ls /boot/dtb-${kver}/$(cat $dtbs_file)
  ls /boot/dtb-${kver}/$(cat $dtbs_file) | xargs printf " -b %s" | xargs mkimage -D "-I dts -O dtb -p 2048" -f auto -A arm64 -O linux -T kernel -C lzma -a 0 -d Image.lzma -i initrd.img.xz kernel.itb || out_of_memory
fi

vbutil_kernel --pack vmlinux.kpart --keyblock /usr/share/vboot/devkeys/kernel.keyblock --signprivate /usr/share/vboot/devkeys/kernel_data_key.vbprivk --version 1 --config cmdline --bootloader bootloader.bin --vmlinuz kernel.itb --arch arm
mv -v vmlinux.kpart "/boot/${CUSTOM_PREFIX}vmlinux.kpart-initrd-${kver}${CUSTOM_SUFFIX}" || out_of_memory

# cleaning up
rm -f Image Image.lzma initrd.img.xz bootloader.bin kernel.itb vmlinux.kpart cmdline
cd ..
rmdir $WORKING_DIR


# final output

# printing results
echo "image put inside \"/boot/${CUSTOM_PREFIX}vmlinux.kpart-initrd-${kver}${CUSTOM_SUFFIX}\""

if [ "$CUSTOM_PREFIX" != "" ] || [ "$CUSTOM_SUFFIX" != "" ];then
  exit
fi

echo "$KERNEL_HASH" > /boot/hash-${kver}

if [ "${NO_FLASH}" != "" ]; then
  exit 0
fi

# auto flashing
load_config

kflash(){
  if [ -f $(dirname $BASH_SOURCE)/vtflash ];then
    $(dirname $BASH_SOURCE)/vtflash $kver yes
  elif [ "$(which vtflash)" != "" ];then # sometimes apt doesn't supply full PATH variable and update initramfs fails
    vtflash $kver yes
  elif [ -f /usr/local/bin/vtflash ];then
    /usr/local/bin/vtflash $kver yes
  else
    echo "vtflash does not seem to be present, unable to automatically flash."
  fi
}

ktest(){
  if [ -f $(dirname $BASH_SOURCE)/vttest ];then
    $(dirname $BASH_SOURCE)/vttest $kver yes
  elif [ "$(which vttest)" != "" ];then # sometimes apt doesn't supply full PATH variable and update initramfs fails
    vttest $kver yes
  elif [ -f /usr/local/bin/vttest ];then
    /usr/local/bin/vttest $kver yes
  else
    echo "vttest does not seem to be present, unable to automatically flash."
  fi
}

if [ "$flash" == "auto" ]; then
  echo "automatic flashing"
  if [ "$kver" == "$(uname -r)" ];then
    kflash
  else
    ktest
    echo "the kernel will be permanently flashed after it successfully boots,"
    echo "to prevent this, remove /etc/velvettools/testing"
    echo -n "$kver" > /etc/velvettools/testing
  fi
elif [ "$flash" == "forced" ];then
  echo "forced main flashing"
  kflash
else # manual
  echo ""
  echo "for single boot only testing:"
  echo ""
  echo "  vttest $kver"
  echo ""
  echo "to always boot this kernel after successful testing:"
  echo ""
  echo "  vtflash $kver"
  echo ""
fi
