#!/bin/bash

# -------------------------------------------------------
# file   : common8k.sh
# purpose: Common functions for imaging and upgrades.
# author : Vittal.S
#
# usage  : common8k
#
# modifications:
# 05-03-10  Initial Creation .
# -------------------------------------------------------

# Constants
readonly LOGTIMESTAMPFORMAT="+%Y/%m/%d-%H:%M:%S"

#Check if osv_version is available
OSV_VERSION=$(whereis -b osv_version.sh | awk '{ print $2 }')
if [ ! -f "$OSV_VERSION" ]; then
   logger --id $$ --priority user.warning "$0: osv_version.sh not found in \$PATH ($PATH), exiting!" >/dev/null 2>&1
   exit 1
fi

# ----------------------------------------------
# function _mount
# arg : none
#    description : a private function for outputing the
#    mount in tabbed format inlcuding bind mount points
#
_mount( )
{

   if [ -h /etc/mtab ]
   then
      MOUNT_CMD="findmnt --fstab --evaluate"
   else
      MOUNT_CMD="mount"
   fi

   ret=`${MOUNT_CMD}`
   res=$?

   echo "$ret"
   return $res

}

_logdetail()
{
    local level="$1"
    local timestamp="$2"
    DETAILED_LOG_FILE="/log/detailed.log"
    shift 2
   
    # Check if the directory exists first, return early if it doesn't
    [ ! -d "$(dirname "${DETAILED_LOG_FILE}")" ] && return 0

    if [ ! -f "$DETAILED_LOG_FILE" ]; then
        touch "$DETAILED_LOG_FILE"
        chmod 755 "$DETAILED_LOG_FILE"
    fi

    printf '%s [%s] [%s:%s]: %s\n' \
        "${level}" \
        "${timestamp}" \
        "$(basename "${BASH_SOURCE[2]:-${_SELF_:-UNDEFINED}}")" \
        "${BASH_LINENO[1]}" \
        "$*" >> "${DETAILED_LOG_FILE}" 2>/dev/null
}


# Pretty print info
loginfo() {
    local timestamp="$(date "${LOGTIMESTAMPFORMAT}")"
	echo -e "\e[32mINFO [${timestamp}]:\e[0m $*" 1>&2
    _logdetail "INFO" "${timestamp}" "$@"
}

# Pretty print warnings
logwarning() {
    local timestamp="$(date "${LOGTIMESTAMPFORMAT}")"
	echo -e "\e[33mWARNING [${timestamp}]:\e[0m $*" 1>&2
    _logdetail "WARNING" "${timestamp}" "$@"
}

# Pretty print errors
logerror() {
    local timestamp="$(date "${LOGTIMESTAMPFORMAT}")"
	echo -e "\e[31mERROR [${timestamp}]:\e[0m $*" 1>&2
    _logdetail "ERROR" "${timestamp}" "$@"
}

# Pretty print debugging messages
logdebug() 
{
	local timestamp="$(date "${LOGTIMESTAMPFORMAT}")"
	[ ${DEBUG:-0} -ne 0 ] && echo -e "\e[34mDEBUG [${timestamp}]:\e[0m $*" 1>&2
    _logdetail "DEBUG" "${timestamp}" "$@"
}

# Print startup debugging info for any script
debug_info_startup_script ( ) {
	logdebug "_SELF_: ${_SELF_}"
	logdebug "_SELFDIR_: ${_SELFDIR_}"
	logdebug "Command line: $0 $*"
	logdebug "Bash: ${BASH_VERSION}"
}

# ------------------------------------------------------------
# function: getcfgvar
# args:
#	$1: node.cfg file path
#	$2: Configuration directive to get value of
#	$3: Variable to save the configuration value to
# description:
#	Get the value of a configuration directive and save it to
#	specified variable
# ------------------------------------------------------------

getcfgvar( ) {
	local cfgfile="$1"
	local cfgarg="$2"
	local cfgvarres="$(cat $cfgfile | grep -v '^#'| \
		grep "^[[:space:]]*${cfgarg}[[:space:]]*:" | \
		sed 's/:/: /' | awk '{ print $2 }' | sed -e 's/[[:space:]]*//g')"

	export "$3"="$cfgvarres"
} 2>/dev/null

# ------------------------------------------------------------
# function: service_exists
# args    :
#	$1: service name as it is expected from /sbin/service
# description:
#   Returns 0 if service_name exists in system, 1 otherwise
# ------------------------------------------------------------

service_exists( ) {
	if service --status-all 2>/dev/null | grep -q "$1"
	then
		# exists
		return 0
	fi

	# does not exist
	return 1
}

# ------------------------------------------------------------
# function: remapvirtualhw
# args    :
#	$1 Value of hardware_platform_id node.cfg directive
#	$2 Value of hw_platform node.cfg directive
#	$3 Value of solution node.cfg directive
# description:
#	Maps virtual machines to real hardware type.
#	The result is set to variable 'hwtyperemapvm'.
# ------------------------------------------------------------
remapvirtualhw( )
{
	hwtyperemapvm="$2"
	if [ "x${2}x" = "xVirtualx" ];
	then
		if [ "x${1}${3}x" = "xV25x" ];
		then
			loginfo "Mapping platform ${2} ${1}${3} to x3250"
			hwtyperemapvm='x3250'
		else
			loginfo "Mapping platform ${2} ${1}${3} to x3650T"
			hwtyperemapvm='x3650T'
		fi
	fi
}

# ------------------------------------------------------------
# function: getDMIbaseboardproductName
# args    : None
# description:
#       Detects the baseboard product name of DMI with the
#       help of dmidecode.
# -------------------------------------------------------------
getDMIbaseboardproductName( ) {
   echo $(dmidecode -s baseboard-product-name 2>/dev/null | grep -v '^#' | awk '{ print $1 }' 2>/dev/null)
}

# ------------------------------------------------------------
# function: getDMIsystemproductName
# args    : None
# description:
#       Detects the system product name of DMI with the
#       help of dmidecode.
# -------------------------------------------------------------
getDMIsystemproductName( ) {
   echo $(dmidecode -s system-product-name 2>/dev/null | grep -v '^#' | sed -e 's/ //g')
}

# ------------------------------------------------------------
# function: getvmtypefromDMI
# args    : None
# description:
#       Detects the virtual type from information of DMI with the
#       help of dmidecode.
#       Exit code is 0 for successful detection, 1 otherwise.
# -------------------------------------------------------------
getvmtypefromDMI( ) {
   local vmType=`getDMIbaseboardproductName`
   if [ -z "$vmType" ]
   then
      vmType=`getDMIsystemproductName`
   fi

   case $vmType in
      *Google*)
         echo "Google";;
      '440BX'|*VMware*Virtual*)
         echo "VMware";;
      *i440FX*)
         echo "Proxmox";;
      *Virtual*|*virtual*)
	 echo "Virtual";;
      *)
         echo "Unknown"
         return 1
   esac

   return 0
}

# ------------------------------------------------------------
# function: gethwtypefromNodeCfg
# args    :
#	$1: node.cfg file path
# description:
#	Detects the hardware type from information of node.cfg.
#	The result is set to variable 'hwtypenodecfg'.
#	Exit code is 0 for successful detection, 1 otherwise and
#	'hwtypenodecfg' variable is empty.
# -------------------------------------------------------------
gethwtypefromNodeCfg( ) {
	local nodecfg=$1
	local virtualized='no'

	# Read directives from node.cfg
	getcfgvar $nodecfg hardware_platform_id hwid
	getcfgvar $nodecfg hw_platform hwplat
	getcfgvar $nodecfg solution sol

	# Check virtual machines

	# Determine the hardware type
	if [ "$hwid" = "V" ] || [ "$hwid" = "v" ] 
	then
		hwtypenodecfg='virtual'
		loginfo "Found supported hardware in node.cfg configuration file: ${hwtypenodecfg}."
		return 0
	fi

	# Check the hardware value found in node.cfg
	case $hwplat in
		##########################################
		# Deprecated after V8R1
		'x345') hwtypenodecfg='x345';;
		'x346') hwtypenodecfg='x346';;
		'RX330') hwtypenodecfg='rx330';;
		'x3650T') hwtypenodecfg='x3650';;
		'x3250') hwtypenodecfg='x3250';;
		'x3250M3') hwtypenodecfg='x3250M3';;
		'x3550M2') hwtypenodecfg='x3550';;
		##########################################
		# V8R1 and above
		'RX200')hwtypenodecfg='rx200';;
		'RX200S7') hwtypenodecfg='rx200s7';;
		'RX2530M1') hwtypenodecfg='rx2530m1';;
		'x3550M3') hwtypenodecfg='x3550M3';;
		'x3550M4') hwtypenodecfg='x3550M4';;
		'x3550M5') hwtypenodecfg='x3550M5';;
		'SR530') hwtypenodecfg='SR530';;
      'SR630') hwtypenodecfg='SR630';;
      'SR630V3') hwtypenodecfg='SR630V3';;
      'GENERIC'|'Generic'|'generic') hwtypenodecfg='Generic';;
		##########################################
		*) hwtypenodecfg='';;
	esac

	# Could not determine what kind of machine node.cfg contains
	if [ -z $hwtypenodecfg ]
	then
		logerror "Cannot find supported hardware in node.cfg configuration file."
		return 1
	else
		loginfo "Found supported hardware in node.cfg configuration file: ${hwtypenodecfg}."
		return 0
	fi
}

# ------------------------------------------------------------
# function: gethwtypefromDMI
# args    : None
# description:
#	Detects the hardware type from information of DMI with the
#	help of dmidecode. The result is set to variable 'hwtypedmi'.
#	Exit code is 0 for successful detection, 1 otherwise and
#	'hwtypedmi' variable is empty.
# -------------------------------------------------------------
gethwtypefromDMI( ) {
	# 1) Try the baseboard-product-name option
	# Note: if dmidecode does not support a newer SMBIOS ver., it outputs hash-preceded (#) warnings about it
	local baseboardproductname=$(getDMIbaseboardproductName)
	case ${baseboardproductname} in
		##########################################
		# Deprecated after V8R1
		'SE7520JR2S') hwtypedmi='x3650';;
		'D2440') hwtypedmi='rx330';;
		'4190') hwtypedmi='x3250';;
		'49Y8470'|'81Y6793') hwtypedmi='x3250M3';;
		'49Y6498'|'49Y6512'|'49Y6486'|'59Y3827') hwtypedmi='x3550';;
		##########################################
		# V8R1 and above
		'D3031') hwtypedmi='rx200';;
		'D3032-A1') hwtypedmi='rx200s7';;
		'D3279-A1') hwtypedmi='rx2530m1';;
		'69Y4438'|'69Y5698'|'94Y7614') hwtypedmi='x3550M3';;
		'00AM544'|'00KG553'|'00J6273'|'00Y7823'|'00KA986') hwtypedmi='x3550M4';;
		'440BX'|'Google'|'i440FX') hwtypedmi='virtual';;
		'00MV249'|'01GR455'|'01KN180') hwtypedmi='x3550M5';;
		*\[7X08CTO1WW\]*|*\[7X08TXN800\]*) hwtypedmi='SR530';;
      '7Z71CTO1WW') hwtypedmi='SR630';;
      *SB27B75787*) hwtypedmi='SR630V3';;
		Virtual*|virtual*) hwtypedmi='virtual';;
		##########################################
		*) hwtypedmi='';;
	esac
	if [ -z ${hwtypedmi} ]
	then
		logwarning "Could not detect hardware type from DMI baseboard-product-name [${baseboardproductname:-EMPTY}], trying next method..."
	else
		loginfo "Detected hardware from DMI table: ${hwtypedmi}"
		return 0
	fi

	# 2) Try the system-product-name option, use switch case globs to relax matches
	# Note: if dmidecode does not support a newer SMBIOS ver., it outputs hash-preceded (#) warnings about it
	local systemproductname=$(getDMIsystemproductName)
	case ${systemproductname} in
		##########################################
		# Deprecated after V8R1
		*x3650T*\[798053X\]*) hwtypedmi='x3650';;
		*RX330S1*) hwtypedmi='rx330';;
		*x3250M2*\[4190AC1\]*) hwtypedmi='x3250';;
		*x3250M3*\[4251AC1\]*) hwtypedmi='x3250M3';;
		*x3550M2*\[7946AC1\]*) hwtypedmi='x3550';;
		##########################################
		# V8R1 and above
		*RX200S6*) hwtypedmi='rx200';;
		*RX200S7*) hwtypedmi='rx200s7';;
		*RX2530M1*) hwtypedmi='rx2530m1';;
		*x3550M3*\[7944AC1\]*|*x3550M3*\[7944PGS\]*)
			hwtypedmi='x3550M3';;
		*x3550M4*\[7914AC1\]*|*x3550M4*\[7914PFK\]*|*x3550M4*\[7914UQW\]*)
			hwtypedmi='x3550M4';;
		*Virtual*|*virtual*|*Google*|*i440FX*) hwtypedmi='virtual';;
		*x3550M5*\[5463Z7S\]*|*x3550M5*\[5463AC1\]*|*x3550M5*\[8869AC1\]*) hwtypedmi='x3550M5';;
		*SR530*\[7X08CTO1WW\]*|*SR530*\[7X08TXN800\]*) hwtypedmi='SR530';;
      *SR630*\[7Z71CTO1WW\]*) hwtypedmi='SR630';;
      *SR630V3*) hwtypedmi='SR630V3';;
		##########################################
		*) hwtypedmi='';;
	esac
	if [ -z ${hwtypedmi} ]
	then
		logwarning "Could not detect hardware type from DMI system-product-name [${systemproductname:-EMPTY}], trying next method..."
	else
		loginfo "Detected hardware from DMI table: ${hwtypedmi}"
		return 0
	fi

	# 3) Try 'Product Name:' line between first 2 DMI handles
	local product_name=$(dmidecode | awk 'BEGIN { copy = 0 }                      \
		/Handle 0x0001/ { copy = 1 }            \
		/Handle 0x0002/ { copy = 0 }            \
		copy { print }' | grep "Product Name:")

	# RX2530M1 and GCP do not have the information inside Handle 0x0001 and 0x0002
	hwtypedmi=$(echo $product_name | awk 'BEGIN { unknown = 1 } \
		/Product Name: System x3650/ { unknown=0; print "x3650" } \
		/Product Name: eserver xSeries 345/ { unknown=0; print "x345" } \
		/Product Name: eserver xSeries 346/ { unknown=0; print "x346" } \
		/Product Name: PRIMERGY RX330/ { unknown=0; print "rx330" } \
		/Product Name: PRIMERGY RX200 S6/ { unknown=0; print "rx200" } \
		/Product Name: PRIMERGY RX200 S7/ { unknown=0; print "rx200s7" } \
		/Product Name: VMware Virtual Platform/ { unknown=0; print "virtual" } \
		/Product Name: IBM System x3250/ { unknown=0; print "x3250" } \
      /Product Name: ThinkSystem SR530/ {unknown=0; print "SR530" } \
		/Product Name: ThinkSystem SR630 V3/ {unknown=0; print "SR630V3" } \
      /Product Name: ThinkSystem SR630/ {unknown=0; print "SR630" } \
		unknown { print ""; exit }')
	if [ -z ${hwtypedmi} ]
	then
		logwarning "Could not detect hardware type from DMI Product Name [${product_name:-EMPTY}], mapping it to Generic hardware..."
		hwtypedmi='Generic'
	else
		loginfo "Detected hardware from DMI table: ${hwtypedmi}."
	fi

	return 0
}

# ------------------------------------------------------------
# function: gethwtypefromuser
# args    : None
# description:
#	Ask the user to choose from a ist of hardware types.
#	The result is set to variable 'hwtypeuser'.
# -------------------------------------------------------------
gethwtypefromuser( ) {
	echo "////////////////////////////////////////////////////////////////////////////////////"
	echo "------------------------------------------------------------------------------------"
	echo "Cannot determine hardware type automatically. This is not a fatal error."
	echo "Check that the BIOS firmware is up to date."
	echo "The information found in hardware DMI table is:"
	echo -n "BaseBoard Manufacturer: "
	dmidecode -s baseboard-manufacturer 2>/dev/null | grep -v '^#'
	echo -n "System Product name: "
	dmidecode -s system-product-name 2>/dev/null | grep -v '^#'
	echo -n "System Baseboard Product Name: "
	dmidecode -s baseboard-product-name 2>/dev/null | grep -v '^#'
	echo "------------------------------------------------------------------------------------"
	echo "////////////////////////////////////////////////////////////////////////////////////"
	echo "Please enter one of following to continue."
	##########################################
	# Deprecated after V8R1
	#echo "   x345    - for series IBM x345"
	#echo "   x346    - for series IBM x346"
	#echo "   RX330   - for series Fujitsu Siemens RX 330 S1"
	#echo "   x3650T  - for series IBM x3650T"
	#echo "   x3250   - for series IBM x3250 M2"
	#echo "   x3250M3 - for series IBM x3250 M3"
	#echo "   x3550M2 - for series IBM x3550 M2"
	##########################################
	# V8R1 and above
	echo "   rx200    - for Fujitsu Siemens RX 200 S6."
	echo "   rx200s7  - for Fujitsu Siemens RX 200 S7."
	echo "   rx2530m1 - for Fujitsu Siemens RX 2530 M1."
	echo "   x3550M3  - for IBM 3550M3."
	echo "   x3550M4  - for IBM/Lenovo 3550M4."
	echo "   x3550M5  - for Lenovo 3550M5."
	echo "   SR530    - for Lenovo SR530."
   echo "   SR630    - for Lenovo SR630."
   echo "   SR630V3  - for Lenovo SR630V3."
	echo "   virtual  - for VMWare virtual machine"
   echo "   Generic  - for generic server hardware"
	# TODO: echo "   shelf    - for generic, off the shelf hardware."
	##########################################
	echo
	read -p "Enter hardware type : " hwtypeuser

	while true
	do
		case $hwtypeuser in
			'rx200'|'rx200s7'|'rx2530m1'|'x3550M3'|'x3550M4'|'x3550M5'|'SR530'|'SR630'|'SR630V3'|'virtual'|'Generic')
				break ;;
			*)
				echo "You typed '${hwtypeuser}' which is not in the list"
				read -p "Enter hardware type : " hwtypeuser
				continue
			;;
		esac
	done

	loginfo "User has chosen hardware type: ${hwtypeuser}"
}

# ------------------------------------------------------------
# function: gethwtype
# args    :
#	$1: node.cfg file path
#	$2: Flag that allows interactivity with user. If set to
#	'yes' the user will be shown a list of supported machines
#	to choose from. If set to 'no' then the function returns
#	without a result and the caller should handle the situation.
# description:
#	Detects the hardware type from information of node.cfg and
#	DMI table with dmidecode.
#	The result is set to variable 'hwtype' accordingly.
#	Exit codes:
#	0 for successful auto-detection, node.cfg and DMI table match. 'hwtype' variable has value.
#	1 on unknown hardware in node.cfg and/or DMI table or known values mismatch. 'hwtype' is empty.
#	2 for proper node.cfg but DMI table mismatch. 'hwtype' variable has node.cfg value.
#	3 for user input on interactive runs. 'hwtype' variable has user chosen value.
#	4 for bad command line arguments. 'hwtype' variable is empty.
# -------------------------------------------------------------
gethwtype( ) {
	local nodecfgpath="$1"
	local interactive="$2"

	if [ -z "$nodecfgpath" ] || [ ! -f "$nodecfgpath" ]
	then
		logerror "gethwtype called with bad node.cfg path argument: $nodecfgpath"
		hwtype=''
		return 4
	fi

	if [[ ( -z $interactive ) || ( "X${interactive}X" != 'XyesX' && "X${interactive}X" != 'XnoX' ) ]]
	then
		logwarning "gethwtype called with bad interactive argument, assuming non interactive use"
		interactive='no'
	fi

	# First detect the type of hardware the main system
	# configuration file contains
	if ! gethwtypefromNodeCfg "${nodecfgpath}"
	then
		logerror "System configuration file contains unknown hardware"
		hwtype=''
	fi

	# Detect the type of the system we are running right now
	# from DMI values
	if ! gethwtypefromDMI
	then
		logwarning "Hardware DMI table contains unknown hardware"
		hwtype=''
	fi

  if [ "${hwtypenodecfg}" = "Generic" ] || [ "${hwtypenodecfg}" = "GENERIC" ] || [ "${hwtypenodecfg}" = "generic" ]
  then
    hwtype=${hwtypenodecfg}
    return 2
  fi

	# Compare the results and make the final decision
	if [ "X${hwtypenodecfg}X" != "X${hwtypedmi}X" ]
	then
		logerror "System configuration file contains hardware [${hwtypenodecfg:-EMPTY}] but detected [${hwtypedmi:-EMPTY}] from hardware DMI table."

		# Unknown DMI value nut known node.cfg
		if [ ! -z "${hwtypenodecfg}" ] && [ -z "${hwtypedmi}" ]
		then
			logwarning "DMI table contains unknown value. The one in node.cfg is properly supported, will continue with this hardware type [${hwtypenodecfg}]."
			hwtype=${hwtypenodecfg}
			return 2
		fi

		# Both known values but no match, no decision could be made
		if [ ! -z "${hwtypenodecfg}" ] && [ ! -z "${hwtypedmi}" ]
		then
			logerror "node.cfg and DMI table contain valid values but they do not match, no decision can be made..."
			hwtype=''
			return 1
		fi
	fi

	if [ -z "${hwtypenodecfg}" ]
	then
		if [ "X${interactive}X" = "XyesX" ]
		then
			gethwtypefromuser
			hwtype=${hwtypeuser}
			loginfo "User decided harware as ${hwtype}."
			return 3
		else
			hwtype=''
			return 1
		fi
	fi

	# Set the variable and return OK
	hwtype=${hwtypedmi}
	loginfo "Determined hardware: ${hwtype}"
	return 0
}

# ------------------------------------------------------------
# function: mapprofile
# args    :
#	$1 solution type string, concatenated by hardware_platform_id
#	and solution. If this option is empty or not set then these
#	configuration directives are read from current system node.cfg
#	with cfgread program.
# description:
#   Maps the node.cfg hardware_platform_id and solution to a
#	system profile. System profiles possible values:
#	standard, integrated, unknown
# -------------------------------------------------------------
mapprofile( ) {
	solutiontype=$1
	#<MapRunningSolution>
	if [ "X${solutiontype}X" = "XX" ];
	then
		curhwid="`cfgread hardware_platform_id`"
		cursolution="`cfgread solution`"
		solutiontype=${curhwid}${cursolution}
	fi
	#</MapRunningSolution>

	unset syssolution
	case $solutiontype in
	'L8') profile="standard";;

	'M8') profile="standard" ;;

	'M9') profile="integrated" ;;

	'M10') profile="integrated" ;;

	'S8') profile="standard" ;;

	'S9') profile="integrated" ;;

	'S10') profile="integrated" ;;

	'T8'|'TM38'|'TM48') profile="standard" ;;

	'T9'|'TM39'|'TM49') profile="integrated" ;;

	'T10'|'TM310'|'TM410') profile="integrated" ;;

	'V8'|'V11'|'V12') profile="standard" ;;

	'V9') profile="integrated" ;;

	'V25')
		profile="integrated"
		syssolution="lowcost"
	;;

	'W8') profile="standard" ;;

	'W9') profile="integrated" ;;

	'W10') profile="integrated" ;;

	'WS68'|'WS78') profile="standard" ;;

	'WS69'|'WS79') profile="integrated" ;;

	'WS610'|'WS710') profile="integrated" ;;

	'X25'|'XM325')
		profile="integrated"
		syssolution="lowcost"
	;;

	'TM326' | 'TM426' | 'WS626' | 'WS726' | 'V26') # CQ00331659, FRN9989
		profile="standard"
	;;

	'PM19') # FSC RX 2530 M1 simplex
		profile="integrated"
	;;

	'PM126' | 'PM18') # FSC RX 2530 M1 duplex
		profile="standard"
	;;

	'TM59') # Lenovo X3550 M5 simplex
		profile="integrated"
	;;

	'TM526' | 'TM58') # Lenovo X3550 M5 duplex
		profile="standard"
	;;

	'SR59') # Lenovo SR530 simplex
		profile="integrated"
	;;

	'SR526' | 'SR58') # Lenovo SR530 duplex
		profile="standard"
	;;

   	'SR69') # Lenovo SR630 simplex
		profile="integrated"
	;;

	'SR626' | 'SR68') # Lenovo SR630 duplex
		profile="standard"
	;;

   	'SR6V39') # Lenovo SR630 V3 simplex
		profile="integrated"
	;;

	'SR6V326' | 'SR6V38') # Lenovo SR630 V3 duplex
		profile="standard"
	;;

   'Generic9') # Generic simplex
		profile="integrated"
	;;

	'Generic26' | 'Generic8') # Generic duplex
		profile="standard"
	;;

	*) profile="unknown" ;;

	esac

	syssolution=${syssolution:-$profile}
}

# ----------------------------------------------------------
# function: textncolor
# description:
#   sets up text in color.
# ----------------------------------------------------------

textncolor( )
{
   if [ "$LOG8k4TOOLKIT" != "" ] && [ -w "$LOG8k4TOOLKIT" ];
   then
      echo "$2" >> $LOG8k4TOOLKIT
   fi
   echo -e ${1}$2${Norm}
}

setmode( )
{
   echo -e $1
}

# ----------------------------------------------------------
# function: lookbusy
# description:
#   looks busy, appreciated sometimes too.
# ----------------------------------------------------------

lookbusy( )
{
   seconds=$1
   basesleep=".1"
   totalsleep=$(echo "$basesleep 5" | awk '{ printf( "%.1f", $1 * $2 ) }')
   count=$(echo "$seconds $totalsleep" | awk '{ printf( "%d", $1 / $2 ) }')
   while [ $count -gt 0 ];
   do
      echo -ne "-\ \r";  sleep $basesleep;
      echo -ne "-| \r";  sleep $basesleep;
      echo -ne "-/\r";   sleep $basesleep;
      echo -ne "--\r";   sleep $basesleep;
      echo -ne "--\r";   sleep $basesleep;
      echo -ne "\r"
      count=$(echo $count 1 | awk '{ printf( "%d", $1 - $2 ) }')
   done
}

# ---------------------------------------------------------------
# function: clearstdin
# args    : None
# description:
#   clears stdin from previous associated data.
# ----------------------------------------------------------------
clearstdin( )
{
	# Only consume stdin if file descriptor 0 (stdin)
	# is open and refers to a terminal.
	if [ -t 0 ]
	then
		while read -r -t 1 -d ""
		do
			read -n 256 -r -s -d ""
		done
	fi
}

# ----------------------------------------------------------------
# function: netrule
# args    : none
# description:
#   output network identification entry for ostype
# ----------------------------------------------------------------

netrule( )
{
   pcibus="$1"
   pcidev="$2"
  
   echo 'SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", KERNELS=="'${pcibus}'", NAME="'${pcidev}'"'
   
}

# ----------------------------------------------------------
# function: get_system_nic_info()
# description:
#  Collects information about the system's network interfaces that are PCI-based.
#  For each PCI network interface, it gathers:
#    - Interface name (e.g., eth0, ens33)
#    - PCI bus ID (e.g., 0000:03:00.0)
#    - MAC address
#  This information is stored in ${RAMDISK}/system_nics in the format:
#    ifname|pci_id|mac_address
# ----------------------------------------------------------
get_system_nic_info()
{
   > "${RAMDISK}/system_nics"

   for iface in /sys/class/net/*; do
      dev=$(readlink -f "$iface/device" 2>/dev/null) || continue

      [[ "$dev" == *"/pci"* ]] || continue

      bus=$(basename "$(readlink "$dev/subsystem" 2>/dev/null)")
      [ "$bus" = "pci" ] || continue

      ifname=$(basename "$iface")

      # PCI bus ID
      pci_id=$(basename "$dev")

      # MAC
      mac=""
      if [ -f "$iface/address" ]; then
         if command -v ethtool >/dev/null 2>&1; then
            mac=$(ethtool -P "$ifname" 2>/dev/null | awk '{print $NF}')
         fi

         if [ -z "$mac" ] || [ "$mac" = "00:00:00:00:00:00" ]; then
            mac=$(cat "$iface/address" 2>/dev/null)
         fi
      fi

      echo "$ifname|$pci_id|$mac" >> "${RAMDISK}/system_nics"
   done
}

# ----------------------------------------------------------
#function: is_mac_address()
#description:
#  Checks if a given value is a valid MAC address.
#  A valid MAC address is in the format XX:XX:XX:XX:XX:XX, where X is a hexadecimal digit.
# ----------------------------------------------------------
is_mac_address()
{
   local val="$1"

   [[ "$val" =~ ^([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}$ ]]
}

# ----------------------------------------------------------
#function: find_nic_bus_id()
#description:
#  Given a node.cfg NIC identifier (MAC address or PCI bus id), searches
#  ${RAMDISK}/system_nics (ifname|pci_id|mac_address, populated by
#  get_system_nic_info) for a match.
#  Prints "ifname|pci_id" on match. Returns 0 on match, 1 if not found.
# ----------------------------------------------------------
find_nic_bus_id()
{
   local nic_id="$1"
   local sys_iface sys_pci sys_mac

   if is_mac_address "$nic_id"; then
      normalized_nic_id=$(echo "$nic_id" | tr '[:upper:]' '[:lower:]' | tr -d ':-')
      while IFS='|' read -r sys_iface sys_pci sys_mac; do
         normalized_sys_mac=$(echo "$sys_mac" | tr '[:upper:]' '[:lower:]' | tr -d ':-')
         if [ "$normalized_nic_id" = "$normalized_sys_mac" ]; then
            echo "${sys_iface}|${sys_pci}"
            return 0
         fi
      done < "${RAMDISK}/system_nics"
   else
      while IFS='|' read -r sys_iface sys_pci sys_mac; do
         if [ "$nic_id" = "$sys_pci" ]; then
            echo "${sys_iface}|${sys_pci}"
            return 0
         fi
      done < "${RAMDISK}/system_nics"
   fi

   return 1
}

# ---------------------------------------------------------------
# function: configure_nics
# args    : udevrules
# description:
#   Generates udev rules for unknown hardware.
#   The function reads the nic_ids from node.cfg. and generates the udevrules
#   The generated rules are written to the provided udevrules file.
# ----------------------------------------------------------------
configure_nics()
{
   CFGPATH=$1
   UDEVNETRULES=/etc/udev/rules.d/70-persistent-net.rules
   curnode="$(uname -n)"

   primnodename=$(grep node_1_name: ${CFGPATH} | awk '{print $NF}')

   current_node=2

   if [ "$curnode" = "$primnodename" ]; then
      current_node=1
   fi

   get_system_nic_info

   if [ ! -s "${RAMDISK}/system_nics" ]; then
      logerror "Could not collect NIC information"
      return 1
   fi

   declare -A bus_owner=()
   local missing_entries=""

   > "$UDEVNETRULES"

   for i in {0..7}
   do
      field="eth"$i"_node${current_node}_id:"

      nic_id="$(grep $field $CFGPATH | awk '{print $NF}')"

      [ -z "$nic_id" ] && continue

      match="$(find_nic_bus_id "$nic_id")"
      # match looks like "eth0|0000:03:00.0" - keep only the part after
      # the "|" (the PCI bus id); empty if there was no match at all
      bus_id="${match##*|}"

      if [ -z "$bus_id" ]; then
         logerror "eth${i}_node${current_node}_id ($nic_id) does not exist in system"
         missing_entries="${missing_entries}  eth${i}_node${current_node}_id: $nic_id\n"
         continue
      fi

      if [ -n "${bus_owner[$bus_id]}" ]; then
         logerror "eth${i}_node${current_node}_id ($nic_id) resolves to bus $bus_id, already used by ${bus_owner[$bus_id]}"
         missing_entries="${missing_entries}  eth${i}_node${current_node}_id: $nic_id (duplicate bus $bus_id, also used by ${bus_owner[$bus_id]})\n"
         continue
      fi

      bus_owner[$bus_id]="eth${i}_node${current_node}_id ($nic_id)"
      netrule "${bus_id}" "eth${i}" >> "$UDEVNETRULES"
   done

   if [ -n "$missing_entries" ]; then
      logerror "NIC ids found in node.cfg do not match with the system's NICs"
      logerror "NIC configuration failed for the following entries:"
      echo -e "$missing_entries"
      logerror "Installation cannot continue."
      logerror "Please verify that the NIC ids (MAC or PCI bus-id) are declared properly in node.cfg and try again."
      return 1
   fi

   loginfo "Nic ids in node.cfg, matched the system ones"

   return 0
}


# ---------------------------------------------------------------
# function: maphw
# args    : None
# description:
#   maps the hardware type in node.cfg to abstract type.
# ---------------------------------------------------------------

maphw( )
{
   hwplat="$(cfgread hw_platform)"
   case $hwplat in
         RX330)
            hwtype="rx330"
            ;;
         RX200)
            hwtype="rx200"
            ;;
         RX200S7)
            hwtype="rx200s7"
            ;;
         x3650T)
            hwtype="x3650"
            ;;
         x345)
            hwtype="x345"
            ;;
         x346)
            hwtype="x346"
            ;;
         x3250)
            hwtype="x3250"
            ;;
         x3250M3)
            hwtype="x3250"
            ;;
         x3550)
            hwtype="x3550"
            ;;
         x3550M3)
            hwtype="x3550M3"
            ;;
         x3550M4)
            hwtype="x3550M4"
            ;;
         SR630V3)
            hwtype="SR630V3"
            ;;
         Virtual)
            hwtype="virtual"
            ;;
         GENERIC|Generic|generic)
            hwtype="Generic"
            ;;
         *)
            hwtype="unknown"
            ;;
   esac
}

# ---------------------------------------------------------------
# function: checkinstalldone
# args    : None
# description:
#   Checks if intsall mode, & if so its really done.
# ---------------------------------------------------------------

checkinstalldone( )
{

   curnode="`uname -n`"
   primnodename="`cfgread node_1_name`"
   secnodename="`cfgread node_2_name`"
   if [ "$curnode" = "$primnodename" ];
   then
      zverify="`pgrep zverify`"
      if [ "$zverify" != "" ];
      then
         while ( true )
         do
            xtree="`pgrep xtree`"
            srxctrl="`pgrep srxctrl`"
            sipsm11pid="`pgrep -f sipsm11`"
            sipsm22pid="`pgrep -f sipsm22`"

            if [ "$xtree" = "" -a "$srxctrl" = "" -a "$sipsm11pid" != "" -a "$sipsm22pid" != "" ];
            then
               echo "common8k:Verified install is done."
               break;
            fi
            sleep 8
         done
      fi
   fi

}

# ---------------------------------------------------------------
# function: check if the PWD is valid
# args    : None
# description:
#   Checks if intsall mode, & if so its really done.
# ---------------------------------------------------------------

checkpwd( )
{
   #<CheckValidPwd>
      if [ "$PWD" != "" ];
      then
         FAIL=2
         if [ -d "${PWD}" ] || [ -L "${PWD}" ];
         then
            echo "common8k: Your current working directory is valid."
         else
            echo "common8k: Your current working directory is not valid."
            echo "        : Change your working directory and try again."
            exit $FAIL
         fi
      fi
   #</CheckValidPwd>
}

# ---------------------------------------------------------------
# function: check if the PWD is valid
# args    : None
# description:
#   checks the status of the node. pass in 'all' 'CE_01' or 'CE_02'
# ---------------------------------------------------------------
healthcheck( )
{
   nodeid=$1
   healthcheckstatus=0
   #<CheckRtpCmd>
       RtpBinDir=/opt/SMAW/SMAWrtp/bin
       if [ -f ${RtpBinDir}/nm_list_processes ];
       then
          RtpListCmd=${RtpBinDir}/nm_list_processes
       else
          if [ -f ${RtpBinDir}/RtpNmListProcesses ];
          then
             RtpListCmd=${RtpBinDir}/RtpNmListProcesses
          else
             RtpListCmd=""
          fi
       fi
   #</CheckRtpCmd>
   if [ "$nodeid" = "all" ];
   then
      failedprocs=$(su - srx -c "$RtpListCmd -a 2>/dev/null"     | \
                                      grep RTP_NM_RUNNING       | \
                                      awk '{ print $3 }' | grep -v $mynode)
   else
      failedprocs=$(su - srx -c "$RtpListCmd -a 2>/dev/null      | \
                                      grep $nodeid 2>/dev/null" | \
                                      grep RTP_NM_RUNNING       | \
                                      awk '{ print $3 }' | grep -v $mynode)
   fi

   if [ "$failedprocs" != "" ];
   then
      healthcheckstatus=2
      echo "common8k: Some processes failed to start."
      for idx in $failedprocs
      do
         echo "   - $idx"
      done
      return
   fi
}

# ---------------------------------------------------------------
# function: oplock
# args    : None
# description:
#   Check & lock upgrade, if we are the only one running.
# ---------------------------------------------------------------

oplock( )
{
   lockopt=$1
   lockstatus=$SUCCESS
   lockfile=/lock/syslock.upgrade
   currentpid=$$
   pid=$$
   case "$lockopt" in
     "force")
         lockpid=`cat $lockfile`
         if [ "$lockpid" != "" ];
         then
            runpid="$(ps -ef f | grep \"upgrade8k\" | grep -v grep | grep -v \" $$ \" | awk '{ print $2 }' | egrep -q \"^${lockpid}$\")"
            if [ "$runpid" != "" ];
            then
               lockstatus=$FAIL
            else
               lockfile -l 1 -s 0 $lockfile
               echo $pid > $lockfile
               chmod 777 $lockfile
            fi
         else
            lockfile -l 1 -s 0 $lockfile
            echo $pid > $lockfile
            chmod 777 $lockfile
         fi
         ;;
     "clean")
         lockfile -l 1 -s 0 $lockfile
         rm -f $lockfile
         ;;
     "exit")
         lockpid=$(cat $lockfile)
         if [ "$lockpid" = "$currentpid" ];
         then
            rm -f $lockfile
         fi
         ;;
     "check")
         lockpid=`cat $lockfile`
         parentpid=${PPID}
         if [ "$lockpid" != "$parentpid" ];
         then
            lockfile -s 1 -r 1 $lockfile
            if [ $? -ne 0 ];
            then
               lockstatus=$FAIL
            else
               rm -f $lockfile
            fi
         fi
         ;;
     "wait")
         lockfile -s 1 $lockfile
         ;;
   esac
   return $lockstatus
} 1>/dev/null 2>&1

# ---------------------------------------------------------------
# function: getAllAncestors
# args    : pid
# description:
#   Get a space separated list of pids containing all the ancestors.
# ---------------------------------------------------------------

getAllAncestors ( )
{
  local pid="${1}"
  local parent="$(awk '{print $4}' /proc/${pid}/stat 2>/dev/null)" || return 1

  #Get all parents
  local ancestorpids=""
  until [ "${parent}" -le 1 ];
  do
    ancestorpids="${ancestorpids} ${parent}"
    parent=$(awk '{print $4}' /proc/${parent}/stat 2>/dev/null) || break
  done

  echo "${ancestorpids}" | xargs
}

# ---------------------------------------------------------------
# function: processCalledByImageUpgrade
# args    : pid
# description:
#   Check if this process is created automatically by the image upgrade.
# ---------------------------------------------------------------

processCalledByImageUpgrade ( )
{
   local pid="$1"
   local ancestors_regex="$(getAllAncestors "${pid}" | tr ' ' '|')"

   # If this is a recursive call do not re-initiate a logging session
   ps -ax | grep -Ew "${ancestors_regex}" | grep -v grep | \
            grep -qE "sh.*(upgrade8k|S19xtree|S99zverify)"

}

# ---------------------------------------------------------------
# function: isOnlyOne
# args    : None
# description:
#   Check if it is the only process being executed.
# ---------------------------------------------------------------

isOnlyOne( )
{
  PIDLOG=/tmp/toolkitpid.log
  INFLOG=/tmp/toolkitinf.log
  rm $PIDLOG 2>/dev/null
  BG_NAME=`basename $0`
  local pscount=0
  local pid=$$

  local ancestors="${pid} $(getAllAncestors "${pid}")"
  local exclude_pids=$(echo "${ancestors}" | tr ' ' '|')

  while ( true )
  do
     #Exclude all parents - not only parent and grandparent
     JOB_RUNNING=`ps -ef | grep "sh.*${BG_NAME}" | grep -v grep | egrep -v " ${exclude_pids} "`
     if [ -z "$JOB_RUNNING" ];
     then
       return 0
     else
       pscount=$[pscount+1]
       if [ $pscount -le 32 ];
       then
          sleep 4
          continue
       fi
       PID_JOB_RUNNING=`echo $JOB_RUNNING  | cut -d ' ' -f 2,3 | cut -d ' ' -f 1`
       echo "$PID_JOB_RUNNING"  > $PIDLOG
       echo "$JOB_RUNNING"      > $INFLOG
       echo "CURRENT PID : $$" >> $INFLOG
       return $FAIL
     fi
  done
}

# ---------------------------------------------------------------
# function: gatherostype
# args    :
#	$1 Chroot directory to search into for the OS type it
# contains. OPTIONAL
#
# description:
#   Detects SLES version and sets the SLESOSTYPE variable
# accordingly to one of these values:
#	SLES12, SLES11, SLES10, ...., etc
# If a directory is provided in the command line it will be used
# as a chroot directory of a SLES system and the function will
# try to look inside it, in order to detect the version of OS
# contained. The files used for the version detection are
# delivered in every SLES system with the sles-release package.
# ---------------------------------------------------------------
gatherostype( ) {
	local chrootdir="$1"

	#<GatherOSType>

	# If the chroot directory to search the OS type into is provided as argument
	if [ "X${chrootdir}X" != "XX" ]
	then
		loginfo "Trying to detect the Operating System type in directory [${chrootdir}]"

		if [ ! -f "${chrootdir}/etc/os-release" -a ! -f "${chrootdir}/etc/SuSE-release" ]
		then
			logerror "Directory [${chrootdir}] does not contain the required OS release files"
			logerror "OS type detection failed."

			return 1
		fi
	fi

	# These files are delivered by sles-release package and are the main
	# authority of the installed SLES version.
	local modern_release_info="${chrootdir}/etc/os-release"		# SLES12 and above
	local legacy_release_info="${chrootdir}/etc/SuSE-release"	# SLES11 and below, deprecated in SLES12 but it is present

	# Empty initialize
	SLESOSTYPE=""

	### Modern cases
	if grep -qi 'VERSION="15.*"' ${modern_release_info} &>/dev/null
	then
		echo "[ostype]: Detected SLES15 Enterprise OS."
		SLESOSTYPE=SLES15
	elif grep -qi 'VERSION="12.*"' ${modern_release_info} &>/dev/null
	then
		echo "[ostype]: Detected SLES12 Enterprise OS."
		SLESOSTYPE=SLES12
	elif [ "X${SLESOSTYPE}X" = "XX" ];
	then
		echo "[ostype]: Unknown OS Type."
		return 1
	fi

	# All OK
	return 0

	#</GatherOSType>
}

# ---------------------------------------------------------------
# function: clstatus
# args    : None
# description:
#   maps to cf status of host based on release sles10,sles11,...
# ---------------------------------------------------------------

clstatus( )
{
  clhost=$1
  mynode=`uname -n`

  if "$OSV_VERSION" --major compare sys ge V7;
  then
     if [ "$clhost" = "$mynode" ];
     then
        lsof -i:47022 1>/dev/null 2>&1
        if [ $? -eq 0 ];
        then
           echo "active"
        else
           echo "down  "
        fi
     else
        /unisphere/srx3000/callp/bin/XcmState -Cv | grep -qi "UP"
        if [ $? -eq 0 ];
        then
           echo "active"
        else
           echo "dead"
        fi
     fi
  else
     cl_status nodestatus $clhost
  fi
}

# ---------------------------------------------------------------
# function: crmmon
# args    : None
# description:
#   maps to crm status of host based on release sles10,sles11,...
# ---------------------------------------------------------------

crmmon( )
{
  sysprimhost=`cfgread node_1_name`
  syssechost=`cfgread node_2_name`
  systestbed=`cfgread test_bed`
  mynode=`uname -n`
  if "$OSV_VERSION" --major compare sys ge V7;
  then
     echo ""
     echo ""
     echo "============"
     echo "Last updated: `date`"
     echo "Current DC: $mynode"
     if [ "$systestbed" = "simplex" ];
     then
        echo "1 Node configured."
     else
        echo "2 Nodes configured."
     fi
     echo "============"
     echo ""
     echo "Node: $sysprimhost: `clstatus $sysprimhost | sed -e 's/active/online/g' -e's/dead/offline/g'`"
     if [ "$systestbed" = "cluster" ];
     then
        echo "Node: $syssechost: `clstatus $syssechost | sed -e 's/active/online/g' -e's/dead/offline/g'`"
     fi
     echo ""
  else
     crm_mon -1
  fi
}

# ---------------------------------------------------------------
# function: keeptrack
# args    : None
# description:
#   send logs to /var/log/keep_track.log
# ---------------------------------------------------------------

keeptrack( )
{
   str="$*"
   {
   echo "Date:            `date`"
   echo "Hostname:        `uname -n`"
   echo "Activity_Type:   $PROC"
   echo "Details:         $str"
   echo ""
   } >> /var/log/keep_track.log 2>/dev/null
}

# ---------------------------------------------------------------
# function: checkmount
# args    : None
# description:
# ---------------------------------------------------------------

checkmount( )
{
   CKMOUNTDIR=$1
   CKMOUNTACTION=$2
   if [ -d "$CKMOUNTDIR" ];
   then
      echo "common8k: Checking for mounts under $CKMOUNTDIR."
      lsof /mnt
      lsofstatus=$?
      if [ -x /bin/mountpoint ];
      then
         mountpoint -q $CKMOUNTDIR
      else
         cat /proc/mounts | cut -d' ' -f2 | egrep -q "^${CKMOUNTDIR}$"
      fi
      mountstatus=$?
      if [ $lsofstatus -eq 0 -o $mountstatus -eq 0 ];
      then
         textncolor $BoldRed "common8k: Sorry, $CKMOUNTDIR is in use."
         echo                "    Hint: Unmount $CKMOUNTDIR and try again."
         if [ "$CKMOUNTACTION" != "" ];
         then
           $CKMOUNTACTION
         fi
         exit $FAIL
      fi
      if [ "`ls -A $CKMOUNTDIR`" != "" ];
      then
         textncolor $BoldRed "common8k: $CKMOUNTDIR not empty. Check it!."
         if [ "$CKMOUNTACTION" != "" ];
         then
           $CKMOUNTACTION
         fi
         exit $FAIL
      fi
   fi
}

jobtimer( )
{
    if [[ $# -eq 0 ]]; then
        echo $(date '+%s')
    else
        local  stime=$1
        etime=$(date '+%s')

        if [[ -z "$stime" ]]; then stime=$etime; fi

        dt=$((etime - stime))
        ds=$((dt % 60))
        dm=$(((dt / 60) % 60))
        dh=$((dt / 3600))
        printf '%d:%02d:%02d' $dh $dm $ds
    fi
}

tty -s
if [ $? -ne 0 ];
then
   source /etc/profile
fi

# performs a tcp connection to specfied port and sends the text message buf
# args :
#       host
#       port
#       message
f_stateclient()
{
   result=$(echo "$3" | netcat $1 $2)
   if [ $? -eq 0 ]
   then
      echo $result
   else
      echo "Error occured in netcat: $result"
   fi

}

# check if a system is OSEE
isOSEE()
{

   mass_deployment="`cfgread mass_deployment`"

   if "$OSV_VERSION" --major compare sys ge V9 && [ "${mass_deployment}" = "Yes" ];
   then
      echo "true"
   else
      echo "false"
   fi

}

# check if a system is V8R1 OSEE
isV8OSEE()
{
   mass_deployment="`cfgread mass_deployment`"

   if "$OSV_VERSION" --major compare sys eq V8 && [ "${mass_deployment}" = "Yes" ];
   then
      echo "true"
   else
      echo "false"
   fi

}

# ----------------------------------------------------------
# function: restoreSecKeys
# description:
#   checks if admin and xchan are shared and restores
#   ipsec keys from specific file
# param :
#    the file containing the sec keys in ASCII
function restoreSecKeys( )
{

   file=$1
   nafo_admin=`cfgread nafo0| awk '{print $2}'`
   nafo_xch=`cfgread nafo3| awk '{print $2}'`

   if [ -f $file -a "X${nafo_admin}X" = "X${nafo_xch}X" ]
   then
      loginfo "Restoring ipsec keys from $file"
      setkey -f $file
   fi

}

# -----------------------------------------------------------------------------------
# function: read_cfg_iso_ver
# description:
#   Reads versions from node.cfg and ISO image file and sets
#   the global array variables __IMG_VERSION__, __CFG_VERSION__.
#   Each array has three values [0] for full, [1] for major and [2] for minor version.
# param :
#   (optional) repository_upload_path
# return:
#   0 = Done, 1 = Error file not found, 2 = Can't read version

read_cfg_iso_ver( )
{
	# Define global variables

	__IMG_VERSION__=""
	__CFG_VERSION__=""


	# Define local variables

	if [ -z ${REPOSITORY} ];
	then
	   declare -r REPOSITORY=/repository
	fi

	declare -r upload_path="${1:-${REPOSITORY}/upload}"
	declare -r img_path="`ls ${upload_path}/*.iso 2>/dev/null | head -1`"
	declare -r cfg_path="`ls ${upload_path}/node.cfg* 2>/dev/null | head -1`"

	# Basic checks before reading values

	if [ "${img_path}" = "" ];
	then
		echo "common8k: Can not find any ISO image file"
		return 1
	fi

	if [ "${cfg_path}" = "" ];
	then
		echo "common8k: Can not find any node.cfg file"
		return 1
	fi


        # Check if version file exists, if not extract it form ISO image

        if [ ! -f ${upload_path}/version ];
	then
                echo "common8k: ISO image file ${img_path} located."
                mount -t iso9660 -o loop,ro ${img_path} /mnt
                if [ ${?} -ne 0 ];
		then
                        echo "common8k: Can not mount ${img_path} image file in order to extract version file."
                        return 1
                fi

                cp -f /mnt/version ${upload_path}/version

                umount -f /mnt
                if [ ${?} -ne 0 ]; then
                        echo "common8k: Can not umount ${img_path} image file from /mnt directory."
                        return 1
                fi
        fi


	# Read ISO image version from extracted version file

        __IMG_VERSION__[0]=`awk '{print $2}' FS=': ' ${upload_path}/version | head -1`
        __IMG_VERSION__[1]=`cut -d "_" -f 1 <<< ${__IMG_VERSION__[0]}`
        __IMG_VERSION__[2]=`cut -d "_" -f 2 <<< ${__IMG_VERSION__[0]}`

        __IMG_VERSION__[1]=${__IMG_VERSION__[1]/#V/}			# Keep the integer only from major version
        __IMG_VERSION__[2]=${__IMG_VERSION__[2]/#R/}			# Kepp the integer only from minor version

	if [ -z "${__IMG_VERSION__[0]}" ] || [ -z "${__IMG_VERSION__[1]}" ] || [ -z "${__IMG_VERSION__[2]}" ];
	then
		echo "common8k: Unable to read ISO image version from 'version' file."
		return 2
	fi


	# Read node.cfg version from srx_build_id value

	__CFG_VERSION__[0]=`fcfgread ${cfg_path} srx_build_id`
	__CFG_VERSION__[1]=`cut -d "." -f 1 <<< ${__CFG_VERSION__[0]}`
	__CFG_VERSION__[2]=`cut -d "." -f 2 <<< ${__CFG_VERSION__[0]}`

        __CFG_VERSION__[1]=${__CFG_VERSION__[1]/#V/}            	# Keep the integer only from major version
        __CFG_VERSION__[2]=$((${__CFG_VERSION__[2]#0}+0))		# Keep the integer only from minor version

	if [ -z "${__CFG_VERSION__[0]}" ] || [ -z "${__CFG_VERSION__[1]}" ] || [ -z "${__CFG_VERSION__[2]}" ];
	then
		echo "common8k: Unable to read srx_build_id major or minor version from ${cfg_path} file."
		return 2
	fi

	#################### VERSION comment explicit workaround ####################
	local COMMENT_VERSION=""
	COMMENT_VERSION[0]=`cat ${cfg_path} | awk '/^# VERSION/ {print $3}'`
        COMMENT_VERSION[1]=`cut -d "." -f 1 <<< ${COMMENT_VERSION[0]}`
        COMMENT_VERSION[2]=`cut -d "." -f 2 <<< ${COMMENT_VERSION[0]}`

        COMMENT_VERSION[1]=$((${COMMENT_VERSION[1]#0}+0))	 # Keep the integer only from major version
        COMMENT_VERSION[2]=$((${COMMENT_VERSION[2]#0}+0))	 # Keep the integer only from minor version

	if [ ! -z "${COMMENT_VERSION[0]}" ] && [ ! -z "${COMMENT_VERSION[1]}" ] && [ ! -z "${COMMENT_VERSION[2]}" ];
	then
		if [ ${__CFG_VERSION__[1]} -eq ${COMMENT_VERSION[1]} ] && [ ${__CFG_VERSION__[2]} -ne ${COMMENT_VERSION[2]} ];
		then
			__CFG_VERSION__[2]=${COMMENT_VERSION[2]}
		fi
	fi
	#############################################################################


	# Print iso image and node.cfg versions

	echo "------------------------------------------------------"
        echo "iso image full version         : ${__IMG_VERSION__[0]}"
	echo "iso image major version        : ${__IMG_VERSION__[1]}"
	echo "iso image minor version        : ${__IMG_VERSION__[2]}"
	echo "------------------------------------------------------"
	echo "node.cfg build full version    : ${__CFG_VERSION__[0]}"
	echo "node.cfg build major version   : ${__CFG_VERSION__[1]}"
        echo "node.cfg build minor version   : ${__CFG_VERSION__[2]}"
	echo "------------------------------------------------------"

	return 0
}

# ----------------------------------------------------------------
# function: getnafodev
# args    : none
# description:
#   get the nafo bonding device in node.cfg
# ----------------------------------------------------------------

getnafodev( )
{

   local nafodev=""
   case $1 in
      bond0)
         nafodev=bonding_dev0
         ;;
      bond1)
         nafodev=bonding_dev1
         ;;
      bond2)
         nafodev=bonding_dev2
         ;;
      bond3)
         nafodev=cluster_dev
         ;;
      *)
         nafodev=$1
         ;;
   esac

   echo "$nafodev"
   return 0
}


# ----------------------------------------------------------------
# function: getSignallingInterfaces
# args    : arg1 : the node role (primary/secondary)
# description:
#   get the signalling interfaces (bond and physical eth) from node.cfg
# ----------------------------------------------------------------

getSignallingInterfaces( )
{

   local noderole=$1

   if [ "$noderole" = "primary" ]
   then
      nafosig="`cfgread nafo1| awk '{ print $2 }'`"
   else if [ "$noderole" = "secondary" ]
   then
      nafosig="`cfgread nafo1| awk '{ print $3 }'`"
   else
      loginfo "getSignallingInterfaces : wrong argument $noderole"
      return 1
   fi
   fi

   local nafodev=`getnafodev $nafosig`
   local nafosigtag=`cfgread $nafodev`

   local bondiface1=`echo $nafosigtag | awk '{print $1}'`
   local bondiface2=`echo $nafosigtag | awk '{print $2}'`

   if [ "$bondiface1" = "$bondiface2" ]
   then
      sigbondset="$nafosig $bondiface1"
   else
      sigbondset="$nafosig $bondiface1 $bondiface2"
   fi

   echo "$sigbondset"
   return 0

}

# ----------------------------------------------------------------
# function: setifarp
# args    : arg1: on/off arg2:ifname
# description:
#   It sets the arp flag on/off on a network interface
#
# ------------
setifarp()
{
   local action=$1
   local ifname=$2

   if [ "$action" != "on" ] && [ "$action" != "off" ]
   then
      return 1
   fi

   ifoutput=$(ifconfig $ifname)

   if [ $? -ne 0 ]
   then
      loginfo "error on getting $ifname ifconfig status, ifconfig error: $ifoutput"
      return 1
   fi

   # enable arp on interface if it was disabled and action is on
   # if action is off the disable arp
   if [ "$action" = "on" ]
   then
      ifoutput=$(ifconfig $ifname arp)
      loginfo "enabling arp on $ifname"
   else
      ifoutput=$(ifconfig $ifname -arp)
      loginfo "disabling arp on $ifname"
   fi

   local ret=$?

   if [ $ret -ne 0 ]
   then
      loginfo "ifconfig failed to set arp to $action, ifconfig error: $ifoutput"
      return 1
   fi

   return 0

}

# ----------------------------------------------------------------
# function: markArpStatus
# args    : arg1: iface , the name of then network interface
# description:
#   It checks if the NOARP flag is on at interface and it populates
#   the global variable has_arp_flag_$iface with true or false
#
# ------------

markArpStatus()
{
   local iface=$1
   ifoutput=$(ifconfig $iface)

   if [ $? -ne 0 ]
   then
      return 1
   fi

   eval has_arp_flag_$iface=false

   echo ${ifoutput}  | grep -q NOARP
   # evaluate a dynamic variable indicating that the
   if [ $? -eq 0 ]
   then
      eval has_arp_flag_$iface=true
   fi

   return 0
}

# -----------------------------------------------------------------------------------
# function: isIPv6Addr
# description:
#   it checks if the argument is a valid IPv6 address
# param :
#      the IP address to check
# return:
#   0 = IPv6, otherwise no IPv6 or error

isIPv6Addr()
{
   local normalize_ip="/unisphere/srx3000/callp/bin/normalize_ip"
   local ipaddr=$1
   local ret=0

   if [ "X${ipaddr}X" = "XX" ]
   then
      return 2
   fi

   if echo ${ipaddr} | grep -q ":"
   then
      if [ -x ${normalize_ip} ]
      then
         ${normalize_ip} ${ipaddr}
         ret=$?
      else
         ret=0
      fi

      return $ret

   else
      return 1
   fi

}

# -----------------------------------------------------------------------------------
# function: getNormalizeIP
# description:
#   return full  IPv6 address in case of IPv6, otherwise it returns arg1
# param :
#      the IP address to check
# return:
#   0 = succes, any other value on error

getNormalizeIP()
{

   local normalize_ip="/unisphere/srx3000/callp/bin/normalize_ip"
   local ipaddr=$1
   local normip=""

   if [ "X${ipaddr}X" = "XX" ]
   then
      return 2
   fi

   if echo ${ipaddr} | grep -q ":"
   then
      if [ -x ${normalize_ip} ]
      then
         normip=`${normalize_ip} -x ${ipaddr}`
         ret=$?
         if [ $ret -eq 0 ]
         then
            echo ${normip}
            return 0
         fi
      fi
   fi

   echo "${ipaddr}"
   return 0
}

# ----------------------------------------------------------------
## function findDataPath
#  description : tries to find from a list of devices the one that is having the node.cfg.primary or node.cfg.secondary
#  arguments: arg1: path for upgrade data ( default /repository/upload )
#  populates the following global variables :
#    USER_DATA_DIR: the path to the user data
#    NEED_UMOUNT: a boolean flag indicating if the path need umount after processing
# return 0 on succes, otherwise 1
# ----------------------------------------------------------------
findDataPath()
{

   NEED_UMOUNT=false
   USER_DATA_DIR=""
   count=0
   local status=1

   while ( true )
   do
      logdebug "Trying to detect the configuration path, try #${count}"

      local floppy="/dev/fd0"
      local ideiso="/dev/hda /dev/hdb /dev/hdc /dev/hdd /dev/hde /dev/sr0 /dev/sr1"
      local scsilist=`sg_map -i | awk '{ print $2 }' | grep -v "/dev/sda" | grep "^/dev/"`
      local fdisklist=`fdisk -l 2>/dev/null | grep -v "/dev/sda" | grep "^/dev" | grep -v grep | awk '{ print $1 }'`
      local auxfdisklist=`fdisk -l 2>/dev/null | grep -v "/dev/sda" | sed -e 's/^Disk //g' | grep "^/dev" | \
                            grep -v grep | awk '{ print $1 }' | sed -e 's/://g'`

      local upgrade_data_path=$1

      local disklist="${upgrade_data_path} ${scsilist} ${fdisklist} ${auxfdisklist} ${floppy} ${ideiso}"

      logdebug "Searching for configuration path in all possible locations [${disklist}]"

      # START - Search all possible paths
      for i in $disklist
      do
         logdebug "Searching for configuration path in [${i}]"

         if [ "$i" != "${upgrade_data_path}" ];
         then
            mount | sort | uniq | grep -e "$i[ \t]*"
            status=$?
            # device is not mounted
            if [ $status -ne 0 ];
            then
               local MNTPATH=/mnt
               NEED_UMOUNT=true
               mount $i $MNTPATH  1>/dev/null 2>&1
               status=$?
               logdebug "mounted $i to $MNTPATH"
            else
               # device is already mounted so we need to get the path
               local MNTENTRY=`mount  | grep -e "$i[ \t]*"`
               local MNTPATH=`echo ${MNTENTRY} | awk '{ print $3 }'`
               NEED_UMOUNT=false
               status=0
            fi
         else
            local MNTPATH=$i
            status=0
            NEED_UMOUNT=false
         fi

         if [ $status -eq 0 ] && [ -f "$MNTPATH/node.cfg.primary" ];
         then
            logdebug "Node.cfg file found in [${i}]"
            USER_DATA_DIR=${MNTPATH}
            return 0
         elif [ $status -eq 0 ] && [ -f "$MNTPATH/node.cfg.secondary" ];
         then
            logdebug "Node.cfg file found in [${i}]"
            USER_DATA_DIR=${MNTPATH}
            return 0
         fi
         # END - Search all possible paths
         if [ "X${NEED_UMOUNT}X" = "XtrueX" ] && [ $status -eq 0 ]
         then
            umount ${MNTPATH}
         fi
      done

      count=$(( count +1 ))
      if [ $count -gt 8 ]
      then
         return 1
      fi

   done

   return 0

}

# ----------------------------------------------------------------
# function: formatStringAsShellInput
# args    : arg1: string to format
# description:
#   Argument is printed in a format that can be reused as shell input
#   escaping non-printable characters withthe proposed POSIX $'' syntax.
# ------------
formatStringAsShellInput( ) {
   echo $(printf "%q\n" "${1}")
}


# ----------------------------------------------------------------
# function: getSshKeysLogsDebug
# args    : none
# description:
#   print the ssh entries and files
#   for toolkit debug
# ------------

getSshKeysLogsDebug( )
{
   for xfiles in /root/.ssh/* /home/solid/.ssh/* /unisphere/srx3000/srx/.ssh/*
   do
      echo " Starting $xfiles "
      cat $xfiles
      echo " Ending $xfiles "
   done
}



# ----------------------------------------------------------------
# function: print_tk_debug 
# args    : optional : log-file
# description:
#   collects extra debug info when upgrade fails
#   when no input logfile is /log/prepare8k.log
# ------------

print_tk_debug ()
{

    TK_LOGFILE=/log/prepare8k.log
    if [ "$1" != "" ]
    then
       TK_LOGFILE="$1"
    fi

    echo "Extra logs " >> $TK_LOGFILE 2>&1
      {
         echo "routes : "
         ip route
         echo "firewalls: "
         iptables -L -n -v
         echo "PFRS from DB: "
         /opt/solid/bin/solsql -x pwdfile:/var/RtpDb/dba.secrets -e "select * from packet_filtering_rule_t" "tcp 16760" dba
         echo "sshd.service: "
         systemctl status sshd.service
         echo "netstat -i : "
         netstat -i
         echo "netstat -nap : "
         netstat -nap
         echo "file system space: "
         df -h
         echo "ssh keys: "
         getSshKeysLogsDebug
         echo "ps -aux: "
         ps -aux
	 echo "xchannel: "
	 xchannel-fips.sh -cfg
	 echo "ip config: "
	 ip a
         
      } >> $TK_LOGFILE 2>&1

}
