#!/bin/sh
# this file is for update of hw161

# shellcheck disable=SC3040
set -o pipefail

#----- includes --------------------------------------------------------

# shellcheck source=../src-rootfs/platform
. /etc/platform  2>/dev/null || true

# platform default values
EEPROM='/sys/bus/i2c/devices/i2c-1/1-0050/eeprom'
{ [ "${platform_type}" = '' ] || [ "${platform_type}" = '%type%' ]; } && platform_type='CS141L'
[ "${platform_oem}"                    = '' ] && platform_oem='012'
[ "${platform_hw}"                     = '' ] && platform_hw='141'
platform_serial="$( dd if="${EEPROM}" skip=256 bs=1 count=11 2>/dev/null)"
platform_macaddr="$(dd if="${EEPROM}" skip=512 bs=1 count=18 2>/dev/null | sed -e 's/://g' | grep -E -o '[0-9a-fA-F]+')"
[ "${platform_feature_typ}"            = '' ] && platform_feature_typ=''
[ "${platform_feature_dtb}"            = '' ] && platform_feature_dtb='box'
[ "${platform_feature_ext_dip_switch}" = '' ] && platform_feature_ext_dip_switch='no'
unset EEPROM

MAC="${platform_macaddr}"
# shellcheck disable=SC3057
MAC="$(printf "%s:%s:%s:%s:%s:%s\n" "${MAC:0:2}" "${MAC:2:2}" "${MAC:4:2}" "${MAC:6:2}" "${MAC:8:2}" "${MAC:10:2}")"

#----- data ------------------------------------------------------------

ARCH="$(find /var/www/lighttpd/upload -name 'update[0-9][0-9][0-9].tar.gz' 2>/dev/null)"

#----- const -----------------------------------------------------------

FILE_MNT='/mnt'

#----- functions -------------------------------------------------------

leds_work () {
    led red   blink_slow
    led green off
}

leds_done () {
    led red   on
    led green off
}

leds_error () {
    led red   blink_fast
    led green off
}

pout () {
    printf "%s\n" "$*"
    sync
}

pok () {
    printf ":: 0 %s\n" "$*"
    sync
    leds_done
    true
}

perr () {
    printf "error: %s\n" "$*" 1>&2
    echo ":: 1 update failed." 1>&2
    sync
    leds_error
    # do not use internal funtions here because of possible recursion!
    mountpoint -q "${FILE_MNT}" && umount "${FILE_MNT}"
    exit 1
}

perr_msg () {
   echo ":: 1" "$@" 1>&2
   sync
   leds_error
   # do not use internal funtions here because of possible recursion!
   mountpoint -q "${FILE_MNT}" && umount "${FILE_MNT}"
   exit 1
}

ext4_format () {
   pout "format block device ${1}:${2} as ext4 filesystem ..."
   mkfs.ext4 -L "${2}" "${1}" < /dev/null > /dev/null || perr "cannot format block device ${1}:${2} as ext4 filesystem"
}

fs_mount () {
   pout "mount ${1} to ${2} ..."
   mount "${1}" "${2}" || perr "cannot mount ${1} to ${2}"
}

fs_umount () {
   pout "umount ${1} ..."
   umount "${1}" || perr "cannot umount ${1}"
}

fs_install () {
   pout "install ${1} to ${FILE_MNT}${1} ..."
   install -m 0644 "${1}" "${FILE_MNT}${1}" || perr "cannot install ${1} to ${FILE_MNT}${1}"
}

fs_install_src () {
   pout "install ${1} to ${FILE_MNT}${2} ..."
   install -m 0644 "${1}" "${FILE_MNT}${2}" || perr "cannot install ${1} to ${FILE_MNT}${2}"
}

fs_install_mode () {
   pout "install ${2} to ${FILE_MNT}${2}:${1} ..."
   install -m "${1}" "${2}" "${FILE_MNT}${2}" || pout "cannot install ${2} to ${FILE_MNT}${2}:${1}"
}

fs_link () {
   # shellcheck disable=SC3043
   local linkname="${1}"
   # shellcheck disable=SC3043
   local linktarget=''
   linktarget="$(readlink "$linkname")"
   if [ "" = "${linktarget}" ]; then
      pout "no linktarget for ${1}, not creating a link!"
      return 0
   fi
   pout "creating symlink ${FILE_MNT}${linkname} to ${linktarget} ..."
   if [ -n "${FILE_MNT}${linktarget}" ]; then
      ln -sf "${linktarget}" "${FILE_MNT}${linkname}" || \
      pout "cannot link ${FILE_MNT}${linkname} to ${linktarget}"
   else
      pout "not creating link, target does not exist ${FILE_MNT}${linktarget}"
   fi
}

fs_install_update_root () {
   pout "install ${ARCH}:rootfs.tar.gz content to ${FILE_MNT} ..."
   ( gunzip -c "${ARCH}" | tar -xOf - 'rootfs.tar.gz' | gunzip -c - | tar -C "${FILE_MNT}" -xf - ) || perr "cannot install ${ARCH}:rootfs.tar.gz to ${FILE_MNT}"
}

fs_install_config () {
   gunzip -c "${ARCH}" | tar -xOf - "${1}" |
   while read -r; do
      # shellcheck disable=SC2030
      REPLY="$(echo "${REPLY}" | grep -E -o '^([0-9]+)[ ]+([^ ]+)')"
      # shellcheck disable=SC3043
      local mode=''
      mode="$(echo "${REPLY}" | cut -d' ' -f1)"
      # shellcheck disable=SC3043
      local file=''
      file="$(echo "${REPLY}" | cut -d' ' -f2)"
      if [ -n "${mode}" ] && [ -n "${file}" ]; then
         fs_install_mode "${mode}" "${file}"
      fi
   done
}

fs_create_link () {
   gunzip -c "${ARCH}" | tar -xOf - "${1}" |
   while read -r; do
      # shellcheck disable=SC2031
      REPLY="$(echo "${REPLY}" | grep -E -o '^([^#].*)')"
      # shellcheck disable=SC3043
      local linkname="$(echo "${REPLY}" | cut -d' ' -f1)"
      if [ -n "${linkname}" ]; then
         fs_link "${linkname}"
      fi
   done
}

process_config () {
   pout "process gxserve config files ..."
   chroot "${FILE_MNT}" "/usr/bin/coreconf" "--workingroot=/" || perr "cannot process gxserve configuration files"
}

env_set_values () {
   pout "update uboot environment with:\n${1}\n..."
   ( echo "${1}" > /tmpuEnv.txt ) || perr "cannot update uboot environment with:\n${1}"
}

# only used during update (not during install)!
check_hw_type () {
   # this file is only used on hw161
   type="161"

   if [ "$type" != "$platform_hw" ]; then
      perr_msg "Hardware revision mismatch. This device requires a firmware for hw$platform_hw. This firmware was, however, identified as valid for hw$type."
   fi

   return 0
}

#----- update -------------------------------------------------------

leds_work

ARCH="/var/www/lighttpd$(echo "${REQUEST_URI}" | grep -E -o '^[^?]+')"
if [ ! -r "${ARCH}" ]; then
    ARCH="/var/www/hiawatha$(echo "${REQUEST_URI}" | grep -E -o '^[^?]+')"
fi
RESET="$(echo "${REQUEST_URI}" | grep -E -o '[\?&](reset)=([^&]+)' | cut -d= -f2 | head -n 1)"
RESET_NET="$(echo "${REQUEST_URI}" | grep -E -o '[\?&](reset_net)=([^&]+)' | cut -d= -f2 | head -n 1)"

[ -r "${ARCH}" ] || perr "cannot find update archive file"

check_hw_type

ROOTFS="$(grep -E -o 'root=/dev/mmcblk1p[23]' /proc/cmdline | grep -E -o '.$')"
if [ "${ROOTFS}" = "2" ]; then
    BOOT='b'
    LABEL='EMMC_B'
    ROOTFS='/dev/mmcblk1p3'
elif [ "${ROOTFS}" = "3" ]; then
    BOOT='a'
    LABEL='EMMC_A'
    ROOTFS='/dev/mmcblk1p2'
else
    perr "fatal: cannot detect root filesystem name"
fi

pout
pout "Parameters:"
pout "  ARCH='${ARCH}'"
pout "  RESET='${RESET}'"
pout "  RESET_NET='${RESET_NET}'"
pout "Next Partition:"
pout "  LABEL='${LABEL}'"
pout

cat >/tmp/platform <<EOF
platform_type='${platform_type}'
platform_oem='${platform_oem}'
platform_hw='${platform_hw}'

platform_serial=${platform_serial}
platform_macaddr=${platform_macaddr}

platform_feature_typ='${platform_feature_typ}'
platform_feature_dtb='${platform_feature_dtb}'
platform_feature_ext_dip_switch='${platform_feature_ext_dip_switch}'
EOF

cat >/tmp/uEnv.txt <<EOF
#----- netconsole -----

ipaddr=10.10.10.10
ncip=10.10.10.11

#----- boot logic -----

uenvcmd=run mmc_gpio
mmc_gpio=if gpio input 28 || gpio input 21; then run mmc_pre; else if ping \${ncip}; then setenv stdout nc; setenv stdin nc; echo \"\\\\cU-Boot# \"; fi; if sleep 1; then run mmc_pre; fi; fi
mmc_pre=run mmc_pre_${BOOT}
mmc_pre_a=if gpio input 5; then run mmc_boot_b; else run mmc_boot_a; fi
mmc_pre_b=if gpio input 5; then run mmc_boot_a; else run mmc_boot_b; fi
mmc_boot_a=setenv mmc_dev 1:2; setenv mmc_root /dev/mmcblk1p2 rw
mmc_boot_b=setenv mmc_dev 1:3; setenv mmc_root /dev/mmcblk1p3 rw

fdtfile=hw161-${platform_feature_dtb}.dtb
mmc_load_fdt=ext4load mmc \${mmc_dev} \${fdtaddr} boot/dtbs/\${fdtfile}
mmc_load_zimage=ext4load mmc \${mmc_dev} \${loadaddr} boot/zImage
EOF

ext4_format "${ROOTFS}" "${LABEL}"
fs_mount "${ROOTFS}" "${FILE_MNT}"
fs_install_update_root
fs_install_src '/tmp/platform' '/etc/platform'
if [ "${RESET}" = 'true' ]; then
    if [ "${RESET_NET}" != "true" ]; then
        fs_install_config 'reset-configfiles'
    fi
else
    fs_install_config 'keep-configfiles'
    fs_create_link 'keep-linknames'
    if [ -f "/etc/hiawatha/server.pem" ]; then
        if [ ! -f "${FILE_MNT}/etc/lighttpd/server.pem" ] || \
           ! cmp -s "/etc/hiawatha/server.pem" "${FILE_MNT}/etc/lighttpd/server.pem"; then
            pout "Migrating legacy /etc/hiawatha/server.pem to /etc/lighttpd/server.pem"
            install -m 0600 "/etc/hiawatha/server.pem" "${FILE_MNT}/etc/lighttpd/server.pem" || \
                pout "warning: cannot migrate /etc/hiawatha/server.pem to ${FILE_MNT}/etc/lighttpd/server.pem"
        fi
    fi
    if [ -d "${FILE_MNT}/var/www/hiawatha" ]; then
        pout "Removing legacy /var/www/hiawatha from preserved data"
        rm -rf "${FILE_MNT}/var/www/hiawatha"
    fi
fi
process_config
fs_umount "${FILE_MNT}"

fs_mount '/dev/mmcblk1p1' "${FILE_MNT}"
fs_install_src '/tmp/uEnv.txt' '/uEnv.txt'
fs_umount "${FILE_MNT}"

pok "emmc successfully updated"

if [ -f "/var/log/update.log" ]; then
    fs_mount "${ROOTFS}" "${FILE_MNT}"
    fs_install_mode "664" "/var/log/update.log"
    chown root.www-data "${FILE_MNT}/var/log/update.log"
    fs_umount "${FILE_MNT}"
fi

reboot
