#
# Copyright 2016 Cumulus Networks Inc.
# All rights reserved
#
# Functions and variables for checking the ONIE version in a platform
# specific way.
#
# This assumes the shell is ash/dash.
#

_is_number()
{
	local str="$1"
	if echo -n "$1" | egrep -q "[^0-9]" ; then
		return 1
	fi
	return 0
}

# Validate the current version component.
# Requirements:
# - component is a non-empty string
# - component is a decimal number
#
# Return Codes:
# 0 -- tested component is greater than required version
# 1 -- tested component is equal to required version
# 2 -- tested component is less than required version
#
# A return code of 0 means this component is OK and there is no need
# to check the remaining, lower order, version components.
#
# A return code of 1 means this component is OK, but we still need to
# check the remaining, lower order, version components.
#
# A return code of 2 means this component is bad and there is no need
# to check the remaining, lower order, version components
#
_check_valid_version()
{
	local current_ver="$1"
	local required_ver="$2"

	[ -n "$current_ver" ] || {
		echo -n 1
		return 1
	}

	_is_number $current_ver || {
		echo -n 1
		return 1
	}

	if [ $current_ver -lt $required_ver ] ; then
		# bad, bail out
		echo -n 1
	elif [ $current_ver -eq $required_ver ] ; then
		# Equal. Check next version component
		echo -n 2
	else
		# Greater than.	 No need to check anymore components
		echo -n 0
	fi
}

_EI_ONIE_VERSION_HELP_URL=
_report_unsupported_onie()
{
	cat <<EOF >&2


***************************************************************
***************************************************************

  Unsupported ONIE version: $(onie-sysinfo -v)
  Minimum required version: $ONIE_FW_NEW_VERSION

  Cumulus Linux is unable to install with this version of ONIE.

  ONIE platform: $(onie-sysinfo -p)

  For help upgrading ONIE on this platform, visit:

    $_EI_ONIE_VERSION_HELP_URL

***************************************************************
***************************************************************

EOF
}

# Platform specific check for dni_3048up
#
# For this platform the ONIE version must be at least
# "2016.05-DNI_V2.0.0".  The agreed to format of the version string
# is: [0-9][0-9][0-9][0-9].[0-9][0-9]-DNI_V[0-9].[0-9].[0-9]
_check_onie_dni_3048up()
{
	local version="$1"
	local onie_version
	local onie_year
	local onie_month
	local dni_version
	local dni_major
	local dni_minor
	local dni_revision
	local rc

	ONIE_FW_NEW_VERSION="2016.05-DNI_V2.0.0"
	ONIE_FW_UPDATE_IMAGE="${_FW_ROOT_PATH}/onie-updater-arm-dni_3048up-r1"

	echo -n "$version" | grep -q -- '-DNI_V' || return 1
	onie_version="${version%%-DNI_V*}"
	[ -n "$onie_version" ] || return 1

	onie_year="${onie_version%%.*}"
	rc=$(_check_valid_version "$onie_year" "2016")
	case $rc in
		0|1)  return $rc ;;
	esac

	onie_month="${onie_version##*.}"
	rc=$(_check_valid_version "$onie_month" "05")
	case $rc in
		0|1)  return $rc ;;
	esac

	dni_version="${version##*-DNI_V}"
	[ -n "$dni_version" ] || return 1

	dni_major="${dni_version%%.*}"
	rc=$(_check_valid_version "$dni_major" "2")
	case $rc in
		0|1)  return $rc ;;
	esac

	dni_minor="${dni_version#*.}"
	dni_minor="${dni_minor%.*}"
	rc=$(_check_valid_version "$dni_minor" "0")
	case $rc in
		0|1)  return $rc ;;
	esac

	dni_revision="${dni_version##*.}"
	rc=$(_check_valid_version "$dni_revision" "0")
	case $rc in
		0|1)  return $rc ;;
	esac

	return 0
}

# Platform specific check for accton_as4610_54
#
# For this platform the ONIE version must be at least
# "2016.05.00.03".  The agreed to format of the version string
# is: [0-9][0-9][0-9][0-9].[0-9][0-9].[0-9][0-9].[0-9][0-9]
_check_onie_accton_as4610_54()
{
	local version="$1"
	local onie_year
	local onie_month
	local act_major
	local act_minor
	local rc

	ONIE_FW_NEW_VERSION="2016.05.00.03"
	ONIE_FW_UPDATE_IMAGE="${_FW_ROOT_PATH}/AS4610-54-r0_ONIE_v2016_05_00_03.updater"

	onie_year="${version%%.*}"
	version="${version#*.}"
	rc=$(_check_valid_version "$onie_year" "2016")
	case $rc in
		0|1)  return $rc ;;
	esac

	onie_month="${version%%.*}"
	version="${version#*.}"
	rc=$(_check_valid_version "$onie_month" "05")
	case $rc in
		0|1)  return $rc ;;
	esac

	act_major="${version%%.*}"
	rc=$(_check_valid_version "$act_major" "0")
	case $rc in
		0|1)  return $rc ;;
	esac

	act_minor="${version#*.}"
	rc=$(_check_valid_version "$act_minor" "3")
	case $rc in
		0|1)  return $rc ;;
	esac

	return 0
}

# Main ONIE check entry point.
#
# This function is called in two separate contexts: a) in ONIE context
# by the Cumulus embedded installer (e-i) and b) in Cumulus Linux
# context by the cumulus-onie-firmware package postinst script.
#
# ONIE context is determined by the presence of the "onie-sysinfo"
# executable.  If it is found ONIE context is assumed, other wise
# Cumulus Linux context is assumed.
#
# Function return codes:
#  0 - The current ONIE version is up to date
#  1 - The current ONIE version is out of date and needs an update
#
# When an update is required the following global variables are set:
#   ONIE_FW_OLD_VERSION  - the old version of ONIE detected
#   ONIE_FW_NEW_VERSION  - the new version of ONIE to install
#   ONIE_FW_UPDATE_IMAGE - file system path to the ONIE update image

ONIE_FW_OLD_VERSION=
ONIE_FW_NEW_VERSION=
ONIE_FW_UPDATE_IMAGE=

onie_fw_check()
{
	# Currently no update checking required for x86_64 machines
	if [ "$(uname -m)" = "x86_64" ] ; then
		return 0
	fi

	local rc=0
	local check_fn
	if which onie-sysinfo > /dev/null ; then
		# ONIE context
		case "$(onie-sysinfo -m)" in
			accton_as4610_54)
				check_fn=_check_onie_accton_as4610_54
				;;
			dni_3048up)
				check_fn=_check_onie_dni_3048up
				;;
			*)
				# Everything else is OK
				return 0
		esac
		ONIE_FW_OLD_VERSION="$(onie-sysinfo -v)"
		_FW_ROOT_PATH="${CL_EMBEDDED_ROOT}/firmware/armel"
	else
		# Cumulus Linux context
		case "$(platform-detect)" in
			accton,as4610_54)
				check_fn=_check_onie_accton_as4610_54
				;;
			dni,3048up)
				check_fn=_check_onie_dni_3048up
				;;
			*)
				# Everything else is OK
				return 0
		esac
		ONIE_FW_OLD_VERSION="$(decode-syseeprom | awk '{ if ($3 == "0x29") { print $5; } }')"
		_FW_ROOT_PATH="/usr/lib/cumulus-onie-firmware/armel"
	fi

	eval $check_fn $ONIE_FW_OLD_VERSION || rc=1

	return $rc
}
