#! /bin/sh
##################################################################################
INSTALL_FEATURE=SILENT_UPDATE
##################################################################################
# install results:
##################################################################################
export INSTALL_SUCCESS_NO_REBOOT=0
export INSTALL_SUCCESS_REBOOT=1
export INSTALL_WRONG_HARDWARE=2
export INSTALL_KERNEL_CHECKSUM=3
export INSTALL_FILESYSTEM_CHECKSUM=4
export INSTALL_URLADER_CHECKSUM=5
export INSTALL_OTHER_ERROR=6
export INSTALL_FIRMWARE_VERSION=7
export INSTALL_DOWNGRADE_NEEDED=8
force_update=n
force_down=n
for i in "$@" ; do
    case $i in
        -f)
            force_update=y
        ;;
        -d)
            force_down=y
        ;;
    esac
done
##################################################################################
# get Kernelversion for further handling (deny update <= 3.x)
##################################################################################
currKver="$(uname -r)"
kversion=""
case ${currKver} in
    [3-9].* )
        kversion="${currKver%%-*}"; kversion="${kversion%.*}";
        echo "install: have Kernel ${currKver} - set kversion '${kversion}'";
        ;;
    *)
        echo "install: updating Kernel '${currKver}' is not supported";
        exit "${INSTALL_FIRMWARE_VERSION}"
        ;;
esac
##################################################################################
echo "install: check and install new firmware ..."
##################################################################################
need_reboot="${INSTALL_SUCCESS_NO_REBOOT}"
# Handle silent update
# nop - don't touch the LEDs here
# AVM watchdog compatibility blurb
if [ -x /sbin/avm_watchdog ]; then
    have_avm_watchdog() { /sbin/avm_watchdog --detect >/dev/null; }
    avm_watchdog() { /sbin/avm_watchdog "$@"; }
    echo_avm_watchdog_cmd() { echo "/sbin/avm_watchdog $*"; }
else
    # Old libwdt, /dev/watchdog is AVM device
    have_avm_watchdog() { test -c /dev/watchdog; }
    avm_watchdog() { echo "$*" > /dev/watchdog; }
    echo_avm_watchdog_cmd() { echo "echo $* > /dev/watchdog"; }
fi
##################################################################################
# install support functions
##################################################################################
abort_update() {
    local code="$1" reason="${2-}"
    echo "${reason:+$reason: }abort update -- set INFO led to off (modul=7, state=1)"
    /bin/update_led_off
    exit "${code}"
}
################################
# accepted list of OEMs:
################################
echo OEM="${OEM}"
# Fritz_Box_HW263
echo testing acceptance for device Fritz_Box_HW263 ...
    if [ ! -z "${OEM}" ] ; then
        oem_found=0
        for i in  avm avme ; do
            if [ "$i" = "${OEM}" ] ; then
                echo "OK - OEM ${OEM} is supported"
                oem_found=1
                break
            fi
        done
        if [ "$oem_found" = "0" ] ; then 
            abort_update "${INSTALL_WRONG_HARDWARE}" "OEM ${OEM} not supported"
        fi
    fi
echo "testing acceptance for device Fritz_Box_HW263 done"
kernel_start=0x00000000
kernel_size=6291456
filesystem_start=0x00000000
filesystem_size=26214400
newFWver=08.20
# Versioninfo:	263.08.20
# Buildnummer:	r125903
# Checkpoint:	8affd7254795216cf8b4644a50570e49d123e2a8
# Boxinfo:	HWID=263;OEM=avm,avme;
#! /bin/sh
##################################################################################
#
# FW Version Pattern: major.middle.minor -- compare middle and minor
#
##################################################################################
versioncmp() {
  local a="$1.0" cmp=$2 b="$3.0";
  while test "${a%%.*}" -eq "${b%%.*}" -a "${a}" != 0 -a "${b}" != 0; do
    a="${a#*.}" b="${b#*.}";
  done
  test "${a%%.*}" "$cmp" "${b%%.*}"
}
##################################################################################
# ascertain update requirements
##################################################################################
currFWver=$(/etc/version -v)
case "$currFWver" in
    [0-9][0-9][0-9].[0-9][0-9].[0-9][0-9]) ;;
    [0-9][0-9][0-9].[0-9][0-9].[0-9][0-9][0-9]) ;;
    *)
    abort_update "${INSTALL_FIRMWARE_VERSION}" "error parsing firmware version"
    ;;
esac
currFWver="${currFWver#*.}" # strip major-part (xx.)
echo "curr: xx.${currFWver}  new: xx.${newFWver}"
##################################################################################
# Downgrade with or w/o factorysettings or normal update ?
##################################################################################
if [ "${force_update}" = "y" ] ; then
    echo "Force: Accept Firmware Version: xx.${newFWver} "
    echo "Force: Downgrade with factorysettings ..."
    /bin/setfactorydefaults
    echo "Force: factorysettings done."
else
    ##################################################################################
    #    (newFW) -lt (currFW) :   trigger update interaction
    ##################################################################################
    if versioncmp "${newFWver}" -lt "${currFWver}" ; then
        echo "warning: Firmware downgrade detected"
        # behaviour for devices which basically are downgradable
        if [ "${force_down}" = "y" ] ; then
            echo "Force: Downgrade w/o factorysettings ..."
            # proceed (ignore downgrade, do not trigger interaction) 
        else
            abort_update "${INSTALL_DOWNGRADE_NEEDED}"
        fi
    fi
    echo "Accept Firmware Version: xx.${newFWver}"
fi
# next: prepare_update
#! /bin/sh
##################################################################################
# prepare install
##################################################################################
# do no longer overwrite/remove /var/post_install
if [ ! -f /var/post_install ] ; then
# create, if not present
  echo "#! /bin/sh" >/var/post_install
fi
# append sequence to /var/post_install
# stop Deamons:
#   - LED- and Operating hours counter
#   - telefon, telnetd
{
echo 'echo $0: start'
echo "sleep 1"
echo "killall run_clock"
echo "if pidof telefon &>/dev/null ; then killall telefon ; fi"
echo "if pidof telnetd &>/dev/null ; then killall telnetd ; fi"
echo "echo MODE=update > /dev/avm_power"
} >>/var/post_install
# still running ?
{
echo "echo still running:"
echo "ps"
echo "lsmod"
echo "sleep 1"
} >>/var/post_install
# next: prepare_update_flash
#! /bin/sh
##################################################################################
# setting files to install
##################################################################################
###########################################
echo "install: ${kversion} getting mtds to install..."
echo install: --mtd------------------------------------------------
var_kernel_mtdnr=$(sed -nr 's/^mtd([[:digit:]]+)[:].*\"reserved-kernel\"$/\1/p' "/proc/mtd")
var_non_res_kernel_mtdnr=$(sed -nr 's/^mtd([[:digit:]]+)[:].*\"kernel\"$/\1/p' "/proc/mtd")
var_fs_mtdnr=$(sed -nr 's/^mtd([[:digit:]]+)[:].*\"reserved-filesystem\"$/\1/p' "/proc/mtd")
# get linux_fs_start
linux_fs_start=$(sed -nr 's/^linux_fs_start[[:space:]]([01])$/\1/p' "${CONFIG_ENVIRONMENT_PATH}/environment")
# get fallbackdefault, if linux_fs_start from env is nonexistent
if [ -z "$linux_fs_start" ] ; then
   echo "linux_fs_start nonexistent - fallback"
   if [ "$var_kernel_mtdnr" -gt "$var_non_res_kernel_mtdnr" ] ; then
      linux_fs_start=0
   else
      linux_fs_start=1
   fi
fi
# toggle slot (once only until reboot)
CURRENTLY_BOOTED_SLOT_FILE="/var/bootedslot"
if ! [ -e "${CURRENTLY_BOOTED_SLOT_FILE}" ] ; then
    echo "${linux_fs_start}" > ${CURRENTLY_BOOTED_SLOT_FILE}
fi
booted_slot=$(cat ${CURRENTLY_BOOTED_SLOT_FILE})
other_slot=$(( 1 - booted_slot ))
# exit on invalid slot info
[ "${other_slot}" -eq "0" ] || [ "${other_slot}" -eq "1" ] \
|| abort_update "${INSTALL_OTHER_ERROR}" "invalid other_slot '${other_slot}'"
[ "${booted_slot}" -eq "0" ] || [ "${booted_slot}" -eq "1" ] \
|| abort_update "${INSTALL_OTHER_ERROR}" "invalid booted_slot '${booted_slot}'"
# check
var_mount_mtd=$(mount | grep "/dev/mtdblock$var_fs_mtdnr")
var_mount_mtd_kernel=$(mount | grep "/dev/mtdblock$var_kernel_mtdnr")
if test -z "$var_kernel_mtdnr" || test -z "$var_non_res_kernel_mtdnr" ; then
    abort_update "${INSTALL_KERNEL_CHECKSUM}" "Kernel mtdblock not found."
elif test -z "$var_fs_mtdnr" ; then
    abort_update "${INSTALL_FILESYSTEM_CHECKSUM}" "Filesystem mtdblock not found."
elif test -n "$var_mount_mtd_kernel" ; then
    abort_update "${INSTALL_KERNEL_CHECKSUM}" "Kernel mtdblock is already in use."
elif test -n "$var_mount_mtd" ; then
    abort_update "${INSTALL_FILESYSTEM_CHECKSUM}" "Filesystem mtdblock is already in use."
fi
echo install: --assert---------------------------------------------
if ! test -d "/var/tmp" ; then
    abort_update "${INSTALL_OTHER_ERROR}" "Directory '/var/tmp' doesn't exist."
elif ! test -f "/var/tmp/kernel.image" ; then
    abort_update "${INSTALL_KERNEL_CHECKSUM}" "File 'kernel.image' doesn't exist."
elif ! test -f "/var/tmp/filesystem.image" ; then
    abort_update "${INSTALL_FILESYSTEM_CHECKSUM}" "File 'filesystem.image' doesn't exist."
elif test -d "/var/tmp/fs" ; then
    abort_update "${INSTALL_FILESYSTEM_CHECKSUM}" "Directory '/var/tmp/fs' already exist."
elif test -d "/var/tmp/fs_mtd" ; then
    abort_update "${INSTALL_FILESYSTEM_CHECKSUM}" "Directory '/var/tmp/fs_mtd' already exist."
fi
echo install: --addr+size------------------------------------------
    kernel_image_size="$(stat -c %s /var/tmp/kernel.image)"
    filesystem_image_size="$(stat -c %s /var/tmp/filesystem.image)"
    echo "install: kernel_start=${kernel_start}"
    echo "install: kernel_size=${kernel_size}"
    echo "install: kernel_image_size=${kernel_image_size}"
    echo "install: filesystem_start=${filesystem_start}"
    echo "install: filesystem_size=${filesystem_size}"
    echo "install: filesystem_image_size=${filesystem_image_size}"
    if [ -z "${kernel_image_size}" ] || [ "${kernel_image_size}" = "0" ]  ; then
        abort_update "${INSTALL_KERNEL_CHECKSUM}" "Kernel Adress or Size error!"
    fi
    if [ -z "${filesystem_image_size}" ] || [ "${filesystem_image_size}" = "0" ]  ; then
        abort_update "${INSTALL_FILESYSTEM_CHECKSUM}" "Filesystem Adress or Size error!"
    fi
###########################################
need_reboot="${INSTALL_SUCCESS_REBOOT}"
###########################################
echo "install: ${kversion} writing commands to install..."
#### DEBUG-EXIT ####
# echo "#### DEBUG-EXIT ####" >>/var/post_install
# echo "exit 0" >>/var/post_install
# echo "####################" >>/var/post_install
####################
# Handle silent update (flash immediate)
updatestore=/var/updatestore
update_flash_cmd_dest=${updatestore}/update_action_flash
rm -rf ${updatestore} && mkdir -p ${updatestore}
echo "#! /bin/sh" >${update_flash_cmd_dest}
{
# watch update process state
    echo "update_state=good"
    echo "sync"
# ---
# prevent leaving corrupt activated slot: 
# reset linux_fs_start to booted_slot (otherslot will be activated later again on success).
    echo "echo reset linux_fs_start to booted_slot '${booted_slot}' before modifying other_slot '${other_slot}'..."
    echo "echo linux_fs_start ${booted_slot} > $CONFIG_ENVIRONMENT_PATH/environment"
# ---
# Delete mtds
    echo "echo Erase mtd partitions '$var_kernel_mtdnr' and '$var_fs_mtdnr' ..."
} >> ${update_flash_cmd_dest}
if [ -x "/sbin/update_kernel" ] && [ -e "/dev/mtd$var_kernel_mtdnr" ] ; then
{
    echo "/sbin/update_kernel -o /dev/mtd$var_kernel_mtdnr"
    echo "/sbin/update_kernel -o /dev/mtd$var_fs_mtdnr"
} >> ${update_flash_cmd_dest}
else
{
    echo "echo mtd $var_kernel_mtdnr erase all > /proc/mtd"
    echo "echo mtd $var_fs_mtdnr erase all > /proc/mtd"
} >> ${update_flash_cmd_dest}
fi
# ---
# Copy kernel image
echo 'echo Copy kernel image...' >>${update_flash_cmd_dest}
[ -n "${update_lock_needed_files}" ] && mv /var/tmp/kernel.image "/var/tmp/kernel.image${update_lock_needed_files}"
if [ -x "/sbin/update_kernel" ] && [ -e "/dev/mtd$var_kernel_mtdnr" ] ; then
    echo "/sbin/update_kernel -i /var/tmp/kernel.image${update_lock_needed_files}  -o /dev/mtd$var_kernel_mtdnr" >>${update_flash_cmd_dest}
else
    echo "cp /var/tmp/kernel.image${update_lock_needed_files} /dev/mtdblock$var_kernel_mtdnr" >>${update_flash_cmd_dest}
fi
{
    echo '[ $? -ne 0 ] && echo failed with error "$?" && update_state=bad'
    echo 'echo Clean up kernel image'
    echo "rm -f /var/tmp/kernel.image${update_lock_needed_files}"
} >>${update_flash_cmd_dest}
# ---
# Copy filesystem image
#### no wrapper
echo 'echo Copy filesystem image ...' >>${update_flash_cmd_dest}
[ -n "${update_lock_needed_files}" ] && mv /var/tmp/filesystem.image "/var/tmp/filesystem.image${update_lock_needed_files}"
if [ -x "/sbin/update_kernel" ] && [ -e "/dev/mtd$var_fs_mtdnr" ] ; then
    echo "/sbin/update_kernel -i /var/tmp/filesystem.image${update_lock_needed_files}  -o /dev/mtd$var_fs_mtdnr" >>${update_flash_cmd_dest}
else
    echo "cp /var/tmp/filesystem.image${update_lock_needed_files} /dev/mtdblock$var_fs_mtdnr" >>${update_flash_cmd_dest}
fi
{
    echo '[ $? -ne 0 ] && echo failed with error "$?" && update_state=bad'
    echo 'echo ... Copy filesystem done'
} >>${update_flash_cmd_dest}
# ---
# ---
# ---
##### TZ_UPDATE
    ##################################################################################
    # trustzone? 
    # 1) do it after a possible Bootloader/SBL-update
    # 2) only if firmwareupdate was good it will be activated (tz may dep. to fw)
if [ -x /var/tzupdate ] ; then
echo "install: /var/tzupdate..."
[ -n "${update_lock_needed_files}" ] && mv /var/tzupdate "/var/tzupdate${update_lock_needed_files}"
{
    echo 'if [ "$update_state" = "good" ] ; then'
    echo '    echo calling /var/tzupdate'
    echo "    /var/tzupdate${update_lock_needed_files} -w"
    echo 'else'
    echo '    echo calling /var/tzupdate skipped due to errors...'
    echo 'fi'
} >>${update_flash_cmd_dest}
fi
##### TZ_UPDATE
# ---
# set urlader field 'linux_fs_start'
{
    echo 'if [ "$update_state" = "good" ] ; then'
    echo '    echo Setting linux_fs_start mirror...'
    echo '    echo Setting linux_fs_start mirror... > /dev/console'
    echo "    echo linux_fs_start ${other_slot} > $CONFIG_ENVIRONMENT_PATH/environment"
    echo "    echo Setting linux_fs_start mirror '${other_slot}' activated"
    echo 'else'
    echo '    echo Setting linux_fs_start skipped due to errors...'
    echo 'fi'
} >>${update_flash_cmd_dest}
# ---
# Handle silent update (flash immediate)
# ---
echo 'if [ "$update_state" = "good" ] ; then return 0; else return 1; fi' >>${update_flash_cmd_dest}
chmod +x ${update_flash_cmd_dest}
# ---
# action flash
echo "update action flash at '${update_flash_cmd_dest}'"
if ${update_flash_cmd_dest} ; then
# success, proceed
# Power LED blinken lassen
echo "give update_state=good to /var/post_install"
{
    echo "update_state=good"
    echo "/bin/update_led_on"
} >>/var/post_install
else
# fail, abort 
echo "give update_state=bad to /var/post_install"
echo "update abort - Flashcmd (silent) failed"
{
    echo "update_state=bad"
    echo "/bin/update_led_off"
} >>/var/post_install
abort_update "${INSTALL_OTHER_ERROR}"
fi
# ---
# ---
# Configrescue
echo "echo -n >/var/tmp/config_write_forbidden" >>/var/post_install
# due to append sequence add exit to prevent accidently second run.
echo "exit 0" >>/var/post_install
chmod +x /var/post_install
# next: tail
#! /bin/sh
##################################################################################
# Special actions - only if everything is fine here!
##################################################################################
##################################################################################
# Handle silent update
# nop - don't touch the LEDs here
##################################################################################
#  returnvalues:  0: no reboot,  1: do reboot
##################################################################################
exit "${need_reboot}"
##################################################################################
