#!/bin/sh
#
# dwl command script written by guillaume catto
# designed to:
#	- manually set the upgrade URL to force the migration
#	- enable/disable the upgrade process
#
# Changelog:
#	- Thu April 22 2010 - Guillaume Catto <guillaume.catto@alcatel-lucent.com>
#	* Fix crms00219212: script creation
#
#	- Wed Jun 23 2010 - Guillaume Catto <guillaume.catto@alcatel-lucent.com>
#	* Add a reason and a owner to the reboot function
#
#	- Wed Aug 25 2010 - Guillaume Catto <guillaume.catto@alcatel-lucent.com>
#	* Fix crms00254927: in case of a force to a new URL, store also the protocol used
#
#	- Wed Jan 12 2011 - Guillaume Catto <guillaume.catto@alcatel-lucent.com>
#	* Fix crms00284851: add support for new settings
#
#	- Tue Mar 29 2011 - Guillaume Catto <guillaume.catto@alcatel-lucent.com>
#	* Fix crms00303424: support the use of tcp ports in STATIC mode
#
#	- Tue Apr 05 2011 - Guillaume Catto <guillaume.catto@alcate-lucent.com>
#	* Fix crms00305633: update CURRENT copy of settings ADMCFG_UPDATE_ENABLE
#	* Fix crms00305406: add hidden option to force a system restoration
#
#	- Wed Apr 27 2011 - Guillaume Catto <guillaume.catto@alcatel-lucent.com>
#	* Fix crms00309673: do not store SSL session IDs
#
#	- Mon Jul 18 2011 - Guillaume Catto <guillaume.catto@alcatel-lucent.com>
#	* Fix crms00326993: add an option to cleanup all upgrade files
#
#	- Mon Aug 01 2011 - Guillaume Catto <guillaume.catto@alcatel-lucent.com>
#	* PR 261789: support VHE2 board
#       
#       - Mon Oct 15 2012 - Jerry ZHOU <jerry.zhou@alcatel-lucent.com>
#       * Fix crms00401786: modification for command "dwl forcerestore"
#
#       - Wed Jan 23 2013 - Ziming Xu <Ziming.b.Xu@alcatel-lucent.com>
#       * PR341502: Reduce Reboot Frequency
#
#	- Tue Feb 18 2013 - Ziming Xu <Ziming.b.Xu@alcatel-lucent.com>
#	* crms00417047: confusion about the style of dmurl update
#
#	- Tue Mar 26 2013 - Ziming Xu <Ziming.b.Xu@alcatel-lucent.com>
#	* Fix crms00427214: dwl config command returns empty string for upgrade file and main server used
#
#       - Tue Mar 24 2015 - Mingju Lai <mingju.lai@alcatle-lucent.com>
#       * Fix crqms00151045: avoid POODLE attack: prevent using SSLv2 and SSLv3
### constants used ###

min_input_entries=1
version="1.28"
upgd_workdir="/config/upgrade"
outputfile="/tmp/temp_profile.xml"
tool="dwl"

### SSL parameters ###

insecure=$(getICTinfo PKI STATUS 2>/dev/null)
ssl_ca=$(getICTinfo PKI CA 2>/dev/null)
ssl_cert=$(getICTinfo PKI CERT 2>/dev/null)
ssl_key=$(getICTinfo PKI CERT_PKEY 2> /dev/null)
ctimeout=10

### Current upgrade settings ###

# crms00427214 zimingxu+
oldserver=$(CLISettings get CURRENT ENETCFG_DM 2> /dev/null)
oldbackupserver=$(CLISettings get CURRENT ENETCFG_DM_BACKUP 2> /dev/null)
oldpath=$(CLISettings get CURRENT ENETCFG_UPGRADE_FILE 2>/dev/null)
# crms00427214 zimingxu-

upgrade_status=$(CLISettings get CURRENT ADMCFG_UPDATE_ENABLE 2>/dev/null)

# +++ crms00284851
update_time_enable=$(CLISettings get CURRENT ADMCFG_UPDATE_TIME_ENABLE 2>/dev/null)
update_time_start=$(CLISettings get CURRENT ADMCFG_UPDATE_TIME_START 2>/dev/null)
update_time_delta=$(CLISettings get CURRENT ADMCFG_UPDATE_TIME_DELTA 2>/dev/null)
# --- crms00284851

### external tools ###

UPGD_SCENARIO="/etc/init.d/upgrade-scenario"
UPGD_STEP1="/etc/init.d/upgrade-step1"
LOGGER=$(which logger)

# +++ crms00305406 +++
RPM_RESTORE_POOL="/config/restore/rpm/"
RPM_FILE_LIST="$RPM_RESTORE_POOL/.base_rpmlist"
# --- crms00305406 ---

# +++ crms00326993 +++
UPGD_STATUS=/config/upgrade/status
# --- crms00326993 ---

# +++ PR 261789 +++
SCENARIO_FILE=/config/upgrade/scenario.xml
# --- PR 261789 ---

#+++ HACK +++ POC +++
process_management=/usr/lib/upgrade/upgrade_scripts.sh
childpid=/var/run/upgrade.pid
#--- HACK --- POC ---


# define_aliases
#---------------
# ARGS:
#   <none>  define macros that are used in the different functions
define_aliases() {
    local -
    set +x

    esc=$'\x1b'
    attr="$esc[7m"
    errorattr="$esc[31;7m"
    default="$esc[0m"
    ROOT=${ROOT:-}
    HOME_ADMIN_SYS="/home/admin"
    HOME_ADMIN_UPG="/system/home/admin"

    alias DEFAULT_DEBUG_OFF="local ldebug=1"
    alias defPS4="PS4=\${PS4_TPLT:-\"\$esc[\$((\$\$%6+31))m+(\$\$)\$FUNCTION:\$esc[0m \"}"
    alias IN_DEBUG="([[ -f $HOME_ADMIN_SYS/.debug.upgrade ]] || [[ -f $HOME_ADMIN_UPG/.debug.upgrade ]])"
    alias IN_NODEBUG="([[ -f $HOME_ADMIN_SYS/.nodebug.upgrade ]] || [[ -f $HOME_ADMIN_UPG/.nodebug.upgrade ]])"
    alias ENTER_FUNCTION="
    [[ \${ldebug:-0} -eq 1 ]] && { local -; set +x; }
    : \"---- ENTER_FUNCTION\"
    : \"\$esc[4mfrom \${EF_function:-unknown()}\${default}\"
    local OIFS=\$IFS IFS=\",\"
    local EF_function=\"\$FUNCTION(\"\"\$*\"\")\"
    IFS=\$OIFS
    local _in_xflag=\${-//[^x]}
    local PS4
    defPS4
    if IN_DEBUG; then
        local -; set -x
    fi
    if IN_NODEBUG; then
        local -; set +x
    fi
    (IFS=\",\"; : \"\${attr}START \$EF_function\${default}\")
    : \"---- ENTER_FUNCTION END\"
    "
# CRMS00312748 END
#   NOTE:
#       - RETURN macro in a short 'if' has to be like
#           [[ -f <file> ]] && { RETURN <ret_code>; }
#         The '{' and '; }' are VERY VERY important
#       - The ret_code has to be an immediate or a variable other than "$?".
#         "$?" is destroyed by the RETURN macro.
    alias RETURN="
    : \"\${attr}LEAVING \$EF_function\${default}\"
    if [[ \"\$_in_xflag\" == \"\${-//[^x]}\" ]]; then
        [[ -n \"\$_in_xflag\" ]] && set -x || set +x
    fi
    return"
}
define_aliases

### usage function ###

# +++ crms00326993 +++
usage() {
	echo "Usage: dwl [upgrade <on|off>]"
	echo "        .. [seturl <force_upgrade_url>]"
	echo "        .. [check]"
	echo "        .. [config]"
	echo "        .. [rmreport]"
	echo "        .. [version]"
	echo "        .. [help]"
	echo ""
	echo "Arguments:"
	echo "  - upgrade <on|off>: enable/disbale the upgrade process"
	echo "  - seturl <force_upgrade_url>: force upgrade using this url"
	echo "  - check: compare insataleld RPMs with the one available on the server"
	echo "  - config: list all settings used"
	echo "  - rmreport: remove all upgrade_report files created by upgrade process"
	echo "  - version: display the current tool's version"
	echo "  - help: display this menu"
}
# --- crms00326993 ---

### logerror function ###

logerror() {
	# Set a syslog message as well as a one on the console
	$LOGGER -t "dwl" -p local0.emerg -s "$1"
}

### display_upgrade_status ###

display_upgrade_status() {
   	local status=""
   	local FUNCTION=display_upgrade_status
   	ENTER_FUNCTION

	: "translate on/off value to true/false"
	case $upgrade_status in
        	"true") status="on";;
        	"false") status="off";;
        	"on"|"off") status=$upgrade_status;;
    	esac

    	echo "  upgrade status: $status"

    	RETURN 0
}

### child_pid_status function ###

child_pid_status() {
	local FUNCTION=child_pid_status
	ENTER_FUNCTION

	RETVAL=0

	if [[ -e $childpid ]]; then 
		echo "Child process is already running"
		CHILDPID=$(cat $childpid)
		RETVAL=1
	fi

	RETURN
}

### set_upgrade_status function ###

set_upgrade_status() {
	local status=$2
	local updated_status
	local base=$1
	local FUNCTION=set_upgrade_status
	ENTER_FUNCTION

	# Check whether a parameter has been send to dwl
	if [ -z $status ]; then
        	display_upgrade_status
        	RETURN $?
    	fi

	: "translate on/off value to true/false"
	case $status in
        	"on") updated_status="true";;
        	"off") updated_status="false";;
        	"true"|"false") updated_status=$status;;
        	*) echo "unrecognized status $status"
    	esac

	logerror "Setting ADMCFG_UPDATE_ENABLE to value \"$updated_status\""

	: "check if upgrade is authorized"
	if [ "$upgrade_status" != "$updated_status" ]; then
		CLISettings set "$base" ADMCFG_UPDATE_ENABLE "$updated_status"
		[ $? -ne 0 ] && { RETURN 1; }
		# +++ crms00305633 +++
		# Do not forget to update CURRENT copy of this setting
		if [ "$base" != "CURRENT" ]; then
			CLISettings set CURRENT ADMCFG_UPDATE_ENABLE "$updated_status"
			[ $? -ne 0 ] && { RETURN 1; }
		fi
		# --- crms00305633 ---
	fi

	RETURN 0
}

### start_scenario function ###

start_scenario() {
# crms00417047 zimingxu+
# PR341502 zimingxu+
        local upgrade_params="ENETCFG_DM=$1 ENETCFG_UPGRADE_FILE=/$2 ENETCFG_DM_PROTOCOL=$3 ENETCFG_DM_PORT=$4"
# PR341502 zimingxu-
# crms00417047 zimingxu-
	local FUNCTION=start_scenario
	ENTER_FUNCTION
    
	# cleanup the upgrade working directory
	rm -f $upgd_workdir/*

	# +++ HACK +++ POC +++
	# execute the upgrade process:
	#	- compute scenario
	#	- execute it
	#
	# Jerry: dwl is user's command, foreground running is appropriate
	
# PR341502 zimingxu+
	$process_management cmdline_args $upgrade_params
# PR341502 zimingxu-

# PR341502 zimingxu+
        [[ $? -gt 2 ]] && { RETURN 1; }
# PR341502 zimingxu-

	echo "scenario for profile $path as been generated"
	RETURN 0
}

### check_download_profile function ###

check_download_profile() {
	local url=$1
	local curlhttpcode

	# Setup curl configuration
	# +++ crms00309673 +++
	local curl_args="-f --silent --show-error --connect-timeout $ctimeout -o $outputfile -D $outputfile.headers --write-out %{http_code} --no-sessionid"
	# --- crms00309673 ---
	local FUNCTION=check_download_profile
	ENTER_FUNCTION

	case ${url%%://*} in
		"http") ;;
		"https")
			# +++ crms00254927
                        # +++ crqms00151045
			curl_args="${curl_args} --cert $ssl_cert --key $ssl_key --tlsv1"
                        # --- crqms00151045
			if [ "$insecure" == "INSECURED" ]; then
				curl_args="${curl_args} -k"
			else
				curl_args="${curl_args} --cacert $ssl_ca"
			fi
			# --- crms00254927
			;;
		*) echo "Unrecognized protocol ${url%%://*}" && { RETURN 1; };;
	esac

	echo "Downloading: $url"

	# Run download
	curlhttpcode=$(curl $curl_args $url 2> /dev/null)
	retval=$?

	# +++ crms00254927
	if [ ${retval} -eq 0 ]; then
		echo "Downloading: curl returns $retval & http code $curlhttpcode"
	else
		echo "Downloading error: curl returns $retval"
	fi
	# --- crms00254927

	RETURN $retval
}


### upgrade_to_url function ###

upgrade_to_url() {
	local previously_locked=0
	local url=$1

	# +++ crms00303412 +++
	local tmpstr=${url#*//}
	local path=${tmpstr#*/}
	local server=${tmpstr%%/*}
	local port=${server##*:}
	# +++ crms00254927
	local protocol=${url%%:*}
	# --- crms00254927

	# +++ PR 261789 +++
	local ret=
	# --- PR 261789 ---
	local FUNCTION=upgrade_to_url
	ENTER_FUNCTION
	# +++ HACK +++ POC +++
	# Before doing any action, verify that a process is not already running
	child_pid_status
	if [[ $RETVAL == 1 ]]; then
		logerror "Upgrade process is already runnning ($CHILDPID), cannot execute action"
		RETURN 1
	fi
	# --- HACK --- POC ---

	# Check if a port is available, if so, split again the $server
	[[ "$port" !=  "$server" ]] && server=${server%%:*} || unset port
	# --- crms00303412 ---

	# check the full URL: a download should success to continue
	check_download_profile "$url"
	[ $? -ne 0 ] && { RETURN 1; }

	# +++ PR 261789 +++
	if [ -z "$server" ] || [ -z "$path" ]; then
		logerror "Failed to parse URL $url"
		RETURN 1
	fi

	# check if upgrade is locked, if so unlock it right here
	if [ "$upgrade_status" != "true" ]; then
		previously_locked=1
		# +++ crms00305633 +++
		set_upgrade_status CURRENT "true"
		# --- crms00305633 ---
		[ $? -ne 0 ] && logerror "Failed to activate upgrade process" && { RETURN 1; }
	fi

	# Build the scenario
	# +++ crms00303412 +++
	# +++ crms00254927
	start_scenario "$server" "$path" "$protocol" "$port"
	# --- crms00254927
	# --- crms00303412 ---
	ret=$?
	[ $ret -ne 0 ] && logerror "Failed to run upgrade using URL $url" && { RETURN $ret; }

	# lock the upgrade now so that no new scenario can be generated
	if [ $previously_locked -eq 1 ]; then
		# +++ crms00305633 +++
		set_upgrade_status CURRENT "false"
		# --- crms00305633 ---
		[ $? -ne 0 ] && logerror "Failed to lock upgrade process" && { RETURN 1; }
	fi

	RETURN $ret
	# --- PR 261789 ---
}

### set_upgrade_url function ###

set_upgrade_url() {
	local url=$1
	local FUNCTION=set_upgrade_url
	ENTER_FUNCTION

	# check that an url has been set
	if [ -z $url ]; then
		echo "Empty URL specified"
		RETURN 1;
	fi

	# Set some logs before continuing
	logerror "Forcing upgrade URL to $url"

	# verify this url
	upgrade_to_url $url
	[ $? -ne 0 ] && { RETURN 1; }

	RETURN 0
}

### check_upgrade function ###

check_upgrade() {
	local FUNCTION=check_upgrade
	ENTER_FUNCTION

	echo "Checking upgrade status:"
	$UPGD_SCENARIO check
	RETURN $?
}

# +++ crms00326993 +++

### rmfile function ###

rmfile() {
	RETVAL=0
	[ ! -f $1 ] && return

	rm -f $@
	RETVAL=$?
	[ $RETVAL -ne 0 ] && logger -s -t upgrade -p local0.WARNING "Failed to remove file(s) $@"
}

### rmreport function ###

rmreport() {
	echo "Removing upgrade_report files"
	rmfile $upgd_workdir/upgrade_report*

	return $RETVAL
}

### rststatus function ###

rststatus() {
	local input=

	echo "WARNING: Resetting upgrade status"
	while [[ "$input" != "No" && "$input" != "Yes" ]]; do
		echo "Are your sure [Yes/No] ? "
		read input
	done
	if [[ "$input" == "Yes" ]]; then
		# reset upgrade status
		echo "STEP=pre0" > $UPGD_STATUS
	
		# Remove also profile's checksum and backup parameters
		rmfile $upgd_workdir/*.sum
		rmfile $upgd_workdir/.serversip.bak

		echo "upgrade status is resetted"
	fi

	return 0
}

# --- crms00326993 ---

### get_upgrade_config function ###

get_upgrade_config() {
	local FUNCTION=get_upgrade_config
	ENTER_FUNCTION

	echo "Upgrade settings used:"
	display_upgrade_status
	echo "  upgrade file: $oldpath"

# +++ crms00284851
	echo "  upgrade time status: $update_time_enable"
	echo "  upgrade time start: $update_time_start"
	echo "  upgrade time delta: $update_time_delta"
# --- crms00284851

	echo "  main server used: $oldserver"
	[ ! -z $oldbackupserver ] && echo "  backup server used: $oldbackupserver"

	RETURN 0
}

# +++ crms00305406 +++
### force system restoration ###

validate_restore() {
	local ret=0 rpm=
	local FUNCTION=validate_restore
	ENTER_FUNCTION

	: "Is file listing RPM base package has been generated ?"
	################################
	if [ ! -f $RPM_FILE_LIST ]; then
        # crms00401786 jerryzh+
		logger -s -t upgrade -p local0.ERR "Missing list of base packages, restore is not authorized"
		RETURN 1
        # crms00401786 jerryzh-
	fi
	
	: "verify all listed packages"
	###################
	while read line; do
		rpm="$RPM_RESTORE_POOL/$line"

		: "Verify that file $rpm exists"
		if [ ! -f $rpm ]; then
			logger -s -t upgrade -p local0.ERR "Missing RPM package $line"
			ret=1
			break
		fi
	done < $RPM_FILE_LIST

	RETURN $ret
}

force_restore() {
	local ret input=
	local FUNCTION=force_restore
	ENTER_FUNCTION

	echo "WARNING: formating SYSTEM partition"
	while [[ "$input" != "No" && "$input" != "Yes" ]]; do
		echo "Are your sure [Yes/No] ? "
		read input
	done
	
	if [[ "$input" == "Yes" ]]; then
		logger -s -t upgrade -p local0.EMERG "System restoration has been requested"
		validate_restore
		ret=$?
		if [ $ret -eq 0 ]; then
			: "Removing kernel image"
			##################
			# +++ crms00326993 +++
			rmfile /boot/zImage
			[ $RETVAL -ne 0 ] && logger -s -t upgrade -p local0.ERR "System restoration failed" && { RETURN $RETVAL; }
			# --- crms00326993 ---

			: "Launch a reboot"
			rebootbyappli --soft --owner upgrade --reason "System restoration requested"
		fi
	else
		ret=1
	fi

	RETURN $ret
}
# --- crms00305406 ---

### main function ###

# check args
if [ $# -lt $min_input_entries ]; then
	echo "Too few paramters set"
	usage
	exit 1
fi

# parse the options
# +++ crms00326993 +++
case $1 in
	"upgrade") set_upgrade_status "LOCAL" "$2"; retval=$?;;
	"seturl") set_upgrade_url "$2"; retval=$?;;
	"check") check_upgrade; retval=$?;;
	"config") get_upgrade_config; retval=$?;;
	"rmreport") rmreport; retval=$?;;
	"rststatus") rststatus; retval=$?;;
	"forcerestore") force_restore; retval=$?;;
	"version")	echo "dwl version $version"; exit 0;;
	"help") usage; exit 0;;
	*) echo "Unrecognized option $1"; usage; exit 1;;
esac
# --- crms00326993 ---

if [ $retval -ne 0 ]; then
	logerror "$tool KO"
	exit 2
fi

echo "$tool OK"
exit 0
