#!/bin/bash

# update-firmware
# This script runs an auto-check and update of firmware.
# The firmware server URL is set in the /etc/rauc/image-update.conf config file.
# This script can be automatically run via cronjob periodically to check for and install new firmware updates.
#
# Usage:
#   update-firmware [options]
#
# Options:
#   -d    Auto-download and install if update is available
#   -b    Auto-reboot after successful installation
#   -n    Skip configuration backup (no config restore)
#   -f    Install from local RAUC bundle file (path required)
#
# Examples:
#   # Check for updates (download and install if available, with auto-reboot)
#   update-firmware -d -b
#
#   # Check for updates only (no install, just report)
#   update-firmware
#
#   # Install from local bundle file
#   update-firmware -f /tmp/firmware.raucb
#
#   # Install from local bundle with auto-reboot
#   update-firmware -f /tmp/firmware.raucb -b
#
#   # Install from local bundle without config backup
#   update-firmware -f /tmp/firmware.raucb -n
#
#   # Download, install, and reboot (skip config backup)
#   update-firmware -d -b -n
#
# Exit Codes:
#   0  - Success (update installed or no update available)
#   1  - Error (download failed, installation failed, or file not found)

# This function logs messages to both the console and the syslog.
# $@ captures all the arguments passed to the function.
log()
{
  echo "$@"
  echo "$@" | logger -t $0
}

# Extract the version string using 'grep' with a regular expression
extract_version() {
  version=$(echo "$1" | sed -E 's/.*-([0-9]{4}\.[0-9]{2}\.[0-9]{2}\.[a-z0-9]+)\..*/\1/')
  echo "$version"
}

# Install firmware bundle and optionally reboot
# $1 - path to RAUC bundle file
install_firmware() {
  local bundle_path="$1"

  if [ ! -f "/usr/bin/rauc" ]; then
    log "/usr/bin/rauc not found. Is RAUC installed?"
    exit 1
  fi

  # Optional: create backup tarball of configuration files
  if [ "$FLAG_CFG_RESTORE" == 'true' ]; then
    log "Creating configuration backup..."
    sysupgrade -b "$CONFIG_TARBALL"
  fi

  log "Installing firmware image..."
  rauc install "$bundle_path"

  if [ $? -ne 0 ]; then
    log "Failed to install firmware image from $bundle_path"
    exit 1
  fi

  log "Firmware installation completed successfully"

  # Remove .extroot-uuid (sd image only, no effect if not present)
  rm -f /overlay/etc/.extroot-uuid

  # Optional auto-reboot
  if [ "$FLAG_AUTO_REBOOT" == 'true' ]; then
    log "Rebooting system..."
    reboot
  fi
}

CONFIG_DIR=/etc/rauc
CONFIG_TARBALL=/data/sysupgrade.tar
FLAG_AUTO_DOWNLOAD_AND_UPDATE='false'
FLAG_AUTO_REBOOT='false'
FLAG_CFG_RESTORE='true'
LOCAL_BUNDLE_PATH=''

# read conf file
source $CONFIG_DIR/image-update.conf

while getopts 'bndf:' flag
do
    case "${flag}" in
        b) FLAG_AUTO_REBOOT='true';;
        n) FLAG_CFG_RESTORE='false';;
        d) FLAG_AUTO_DOWNLOAD_AND_UPDATE='true';;
        f) LOCAL_BUNDLE_PATH="$OPTARG";;
    esac
done

# If local bundle path is provided, install it directly
if [ -n "$LOCAL_BUNDLE_PATH" ]; then
    if [ ! -f "$LOCAL_BUNDLE_PATH" ]; then
        log "Error: Local bundle file not found: $LOCAL_BUNDLE_PATH"
        exit 1
    fi

    log "Installing firmware from local bundle: $LOCAL_BUNDLE_PATH"
    install_firmware "$LOCAL_BUNDLE_PATH"
    exit 0
fi

# Download and read latest version file
wget -q -O $download_dir/latest-version "$image_update_url/latest-version"
if [ ! $? == 0 ]; then
    log "Failed to download $image_update_url/latest-version"
    exit -1
fi

# Download successful. Assign the content to the variable LATEST_VERSION
LATEST_VERSION=$(cat $download_dir/latest-version)

# Check if the variable LATEST_VERSION is valid
if [ -z "$LATEST_VERSION" ]; then
    log "The file latest-version is empty."
    exit -1
fi

# Read current version.
CURRENT_VERSION=$(cat $CONFIG_DIR/version)

# check if latest version and current version are the same
if [ ! "$CURRENT_VERSION" == "$LATEST_VERSION" ]; then
    log "Update available"
    log "Current version: $(extract_version $CURRENT_VERSION)"
    log "Latest version: $(extract_version $LATEST_VERSION)"

    # check auto download and update flag
    if [ $FLAG_AUTO_DOWNLOAD_AND_UPDATE == 'false' ]; then
        exit 0;
    fi

    # remove any old image files
    rm -f $download_dir/*.raucb

    # download new firmware version
    log "Downloading $LATEST_VERSION from $image_update_url..."
    wget -q -O $download_dir/$LATEST_VERSION "$image_update_url/$LATEST_VERSION"

    if [ ! $? == 0 ]; then
        log "Failed to download $image_update_url/$LATEST_VERSION"
        exit -1
    else
        log "Download Complete."
    fi

    log "Installing firmware image $(extract_version $LATEST_VERSION)..."
    install_firmware "$download_dir/$LATEST_VERSION"

    # Remove downloaded firmware image
    rm -f $download_dir/*.raucb

    exit 0

else
    log Current version $(extract_version $CURRENT_VERSION) is already the latest.
    exit 0
fi
