#/!bin/sh

# Firmware upgrade sequence
# 
# Usage:
#    fwupgrade <Default> <ServerIP> <FileName>
#
# Parameters:
#    <Default>  0: Do not reset default
#               1: Reset default config
#    <ServerIP> 192.168.1.2 (for example)
#    <FileName> V3K9.all (for example)
#    <FromWeb>  1: firmware already in /tmp, skip tftp
#

RESET_DEFAULT=$1
SERVER_IP=$2
FILE_NAME=$3
FROM_WEB=$4

[ "$FROM_WEB" = "1" ] || {
	### Get image file from TFTP server
	[ -f /tmp/$FILE_NAME ] && {
		echo "Firmware Update: Image file already exist in temp dir, delete it."
		rm -f /tmp/$FILE_NAME
	}
	echo "Firmware Update: Downloading image file from server."
	tftp -g -r $FILE_NAME -l /tmp/$FILE_NAME $SERVER_IP >/dev/null 2>&1
	echo "Firmware Update: Download OK"
	###### TODO: if out of ram?
}
[ "$FROM_WEB" = "1" ] && {
	mtd fw_printenv 1 > /tmp/tmp_fw_file
	WEB_FILE_NAME=`grep 'tmpfile' /tmp/tmp_fw_file`
	variable=${WEB_FILE_NAME%%=*}
	tmp=${WEB_FILE_NAME#$variable}
	WEB_FILE_NAME=${tmp#=}
	# for TR069 using fix file name V3K9.ALL
	[ -f /tmp/$WEB_FILE_NAME ] && FILE_NAME=$WEB_FILE_NAME
}

### ==== HTTP start here ====
json set firmware status=upgradeProcess

### Check if firmware image exist
[ -f /tmp/$FILE_NAME ] || {
	echo "Firmware Update: Firmware image not exist."
	json set firmware status=upgradeFail_1
	exit 1
}

### Checksum
echo "Firmware Update: Checking if the firmware is valid"
rm -f /tmp/firmware_header
dd if=/tmp/$FILE_NAME of=/tmp/firmware_header bs=1 count=32 >/dev/null 2>&1
SUM_MD5=
	eval `cat /tmp/firmware_header |
	awk '{
	print "SUM_MD5=" $1}'`
echo "Firmware Update: Extracting firmware..."
copy_to_data=0
dd if=/tmp/$FILE_NAME of=/tmp/V3K9_unchecked.all bs=42 skip=1 >/dev/null 2>&1
RETURN_VALUE=$?
if [ $RETURN_VALUE -ne 0 ]
then
	echo "Firmware Update: Failed to copy firmware to RAM"
	rm -f /tmp/V3K9_unchecked.all
	echo "Firmware Update: copy firmware to flash"
	#rm -f /tmp/$FILE_NAME
	#json set firmware status=upgradeFail_5
	#exit 1
	dd if=/tmp/$FILE_NAME of=/data/V3K9_unchecked.all bs=42 skip=1 >/dev/null 2>&1
	RETURN_VALUE=$?
	if [ $RETURN_VALUE -ne 0 ]
	then
		echo "Firmware Update: Failed to copy firmware to flash. from data"
		rm -f /data/V3K9_unchecked.all
		rm -f /tmp/$FILE_NAME
		json set firmware status=upgradeFail_5
		exit 1
	else
		SUM_MD5_MY=
			eval `md5sum /data/V3K9_unchecked.all |
			awk '{
			print "SUM_MD5_MY=" $1}'`
		
		if [ "$SUM_MD5" = "$SUM_MD5_MY" ]
		then
			echo "Firmware Update: Checksum passed. from data"
			rm -f /data/V3K9_unchecked.all
			copy_to_data=1
		else
			echo "Firmware Update: Checksum error. Abort. from data"
			rm -f /data/V3K9_unchecked.all
			rm -f /tmp/$FILE_NAME
			json set firmware status=firmwareFileInvalid
			exit 1
		fi
	fi
else
	SUM_MD5_MY=
		eval `md5sum /tmp/V3K9_unchecked.all |
		awk '{
		print "SUM_MD5_MY=" $1}'`

	#echo "Output the checksum value for test:"
	#echo $SUM_MD5
	#echo $SUM_MD5_MY

	if [ "$SUM_MD5" = "$SUM_MD5_MY" ]
	then
		echo "Firmware Update: Checksum passed. from tmp"
		rm -f /tmp/V3K9_unchecked.all
	else
		echo "Firmware Update: Checksum error. Abort. from tmp"
		rm -f /tmp/V3K9_unchecked.all
		#rm -f /tmp/$FILE_NAME
		#json set firmware status=firmwareFileInvalid
		#exit 1		
		echo "Firmware Update: copy firmware to flash"		
		dd if=/tmp/$FILE_NAME of=/data/V3K9_unchecked.all bs=42 skip=1 >/dev/null 2>&1
		RETURN_VALUE=$?
		if [ $RETURN_VALUE -ne 0 ]
		then
			echo "Firmware Update: Failed to copy firmware to flash. from data"
			rm -f /data/V3K9_unchecked.all
			rm -f /tmp/$FILE_NAME
			json set firmware status=upgradeFail_5
			exit 1
		else
			SUM_MD5_MY=
				eval `md5sum /data/V3K9_unchecked.all |
				awk '{
				print "SUM_MD5_MY=" $1}'`
			
			if [ "$SUM_MD5" = "$SUM_MD5_MY" ]
			then
				echo "Firmware Update: Checksum passed. from data"
				rm -f /data/V3K9_unchecked.all
				copy_to_data=1
			else
				echo "Firmware Update: Checksum error. Abort. from data"
				rm -f /data/V3K9_unchecked.all
				rm -f /tmp/$FILE_NAME
				json set firmware status=firmwareFileInvalid
				exit 1
			fi
		fi
	fi
fi
# for .rst firm
dd if=/tmp/$FILE_NAME of=/tmp/fwupgrade_rst bs=1 skip=45 count=1 >/dev/null 2>&1
RETURN_VALUE=$?
if [ $RETURN_VALUE -ne 0 ]
then
	echo "Firmware Reset Default: Failed to copy firmware to flash"
	rm -f /tmp/fwupgrade_rst
	rm -f /tmp/$FILE_NAME
	json set firmware status=upgradeFail_6
	exit 1
fi
DEFAULT_RST=`cat /tmp/fwupgrade_rst`	

if [ "$FROM_WEB" != "1" -a -f /etc/persistence/data/fwupgrade_reset_default ];then
	echo "Firmware Update: Another firmware upgrade sequence is processing. Abort."
	json set firmware status=upgradeFail_7
	exit 1
fi

FWRST=$FILE_NAME
FWRST1=${FWRST%%.*}
FWRST=${FWRST#$FWRST1}

if [ "$DEFAULT_RST" = "1" -o "$FWRST" = ".rst" ]; then
	RESET_DEFAULT=1
	#set reset default flag later
	#touch /etc/persistence/data/fwupgrade_reset_default
fi
	
# Check firmware model
dd if=/tmp/$FILE_NAME of=/tmp/check_fw_model bs=1 skip=42 count=2 >/dev/null 2>&1
RETURN_VALUE=$?
if [ $RETURN_VALUE -ne 0 ]
then
	echo "Firmware Reset Default: Failed to copy firmware to flash"
	rm -f /tmp/check_fw_model
	rm -f /tmp/$FILE_NAME
	json set firmware status=upgradeFail_8
	exit 1
fi

FS_MODEL=`cat /tmp/check_fw_model`
MY_MODEL=`grep 'Vigor' /etc/version`
MY_MODEL=${MY_MODEL%% *}

dd if=/tmp/$FILE_NAME of=/tmp/fwupgrade_change_model bs=1 skip=44 count=1 >/dev/null 2>&1
RETURN_VALUE=$?
if [ $RETURN_VALUE -ne 0 ]
then
	echo "Firmware Reset Default: Failed to copy firmware to flash"
	rm -f /tmp/fwupgrade_rst
	rm -f /tmp/$FILE_NAME
	json set firmware status=upgradeFail_10
	exit 1
fi
CHANGE_MODEL=`cat /tmp/fwupgrade_change_model`	

if [ "$FS_MODEL" = "X2" ]; then
	if [ "$CHANGE_MODEL" = "1" ]; then
		[ "$MY_MODEL" = "Vigor300B" ] || {
			echo "Firmware Update: Illegal firmware"
			json set firmware status=upgradeFail_11
			exit 1
		}
		mtd fw_setenv change_fw_eeprom_uboot 1
	else
		[ "$MY_MODEL" = "Vigor2960" -o "$MY_MODEL" = "Vigor2960F" ] || {
			echo "Firmware Update: Illegal firmware"
			json set firmware status=upgradeFail_9
			exit 1
		}
	fi
fi

if [ "$FS_MODEL" = "39" ]; then
	[ "$MY_MODEL" = "Vigor3900" ] || {
		echo "Firmware Update: Illegal firmware"
		json set firmware status=upgradeFail_9
		exit 1
	}
fi 
if [ "$FS_MODEL" = "V3" ]; then
	if [ "$CHANGE_MODEL" = "1" ]; then
		[ "$MY_MODEL" = "Vigor2960" -o "$MY_MODEL" = "Vigor2960F" ] || {
			echo "Firmware Update: Illegal firmware"
			json set firmware status=upgradeFail_11
			exit 1
		}
		mtd fw_setenv change_fw_eeprom_uboot 1
	else 
		[ "$MY_MODEL" = "Vigor300B" ] || {
		echo "Firmware Update: Illegal firmware"
		json set firmware status=upgradeFail_9
		exit 1
	}
	fi	
fi 

	
# Old mechanism----------
### Check if upgrade already processing
#[ -f /tmp/upgrading_firmware ] && {
#	RUNNING_SCRIPT=`ps | grep fwupgrade | wc | awk '{print $1}'`
#	if [ $RUNNING_SCRIPT -ne 1 ]
#	then
#		echo "Firmware Update: Another firmware upgrade sequence is processing. Abort."
#		json set firmware status=upgradeFail_2
#		exit 1
#	else
#		echo "Firmware Update: Abnormal situation, upgrade anyway."
#	fi
#}
#touch /tmp/upgrading_firmware
#------------------------

### New mechanism: Check upgrade and lock
if [ -d /tmp/upgrading_firmware ]; then
	if [ -f /tmp/upgrading_firmware/last_time ]; then
		last_time=`cat /tmp/upgrading_firmware/last_time`
		[ "$last_time" ] || $last_time=0
		time_limit=$(($last_time + 900)) #time out: 900 seconds
		current_time=`cat /proc/uptime |sed 's/\..*//g'`
		if [ $current_time -lt $time_limit ]; then
			echo "Firmware Update: Another firmware upgrade sequence is processing. Abort."
			json set firmware status=upgradeFail_2
			exit 1
		else
			mtd fw_setenv fwup 0
			echo "Firmware Update: Last upgrade time out, upgrade anyway."
		fi
	else
		mtd fw_setenv fwup 0
		echo "Firmware Update: Abnormal situation, upgrade anyway."
	fi
else
	mkdir /tmp/upgrading_firmware
fi
cat /proc/uptime |sed 's/\..*//g' > /tmp/upgrading_firmware/last_time

### Stop processes
echo "Firmware Update: Shutting down applications"
##### TODO: what apps should be shut down?
# 2130_SHUTDOWN_APPS="ipsec samba miniupnpd rp-l2tpd httpd matrixssl lighttpd telnet dropbear"
SHUTDOWN_APPS="asterisk"
for app in $SHUTDOWN_APPS; do
	[ -x /etc/init.d/$app ] && /etc/init.d/$app stop >/dev/null 2>&1
done

### Prepare firmware
echo "Firmware Update: Preparing firmware..."
if [ "$copy_to_data" = 1 ] ; then
	fw_tmp=data
else
	fw_tmp=tmp
fi
rm -f /$fw_tmp/root.ubifs-ubinized
dd if=/tmp/$FILE_NAME of=/$fw_tmp/root.ubifs-ubinized bs=48 skip=1 >/dev/null 2>&1
RETURN_VALUE=$?
if [ $RETURN_VALUE -ne 0 ]
then
	echo "Firmware Update: Image preparing failed. Please upgrade again. from $fw_tmp"
	rm -rf /tmp/upgrading_firmware
	json set firmware status=upgradeFail_3
	exit 1
fi

### Write flash
mtd fw_setenv fs2_status new_fweb
echo "[UPGRADE] Starting writing fs2..." > /dev/console
echo "Firmware Update: Writing image to flash. Do not turn off or reboot the machine. from $fw_tmp"
#mtd write /tmp/root.ubifs-ubinized fs2
#nandwrite -a -m -q /dev/mtd4 /tmp/root.ubifs-ubinized
ubiformat /dev/mtd4 -q -y -s 512 -O 512 -f /$fw_tmp/root.ubifs-ubinized
RETURN_VALUE=$?
#echo $RETURN_VALUE
if [ $RETURN_VALUE -ne 0 ]
then
	echo "Firmware Update: Image writing failed. Please upgrade again. from $fw_tmp"
	rm -rf /tmp/upgrading_firmware
	json set firmware status=upgradeFail_4
	exit 1
else
	#set firmware size
	fwsize=`ls -l /tmp/$FILE_NAME |awk '{print $5}'`
	fwsize=$(($fwsize - 48))
	fwsize=`printf "%x" $fwsize`
	mtd fw_setenv webfwsize $fwsize

	echo "Firmware Update: Upgrade success. from $fw_tmp"
	mtd fw_setenv fs2_status new_ok
	mtd fw_setenv fwup 1
	if [ "$RESET_DEFAULT" == "1" ]; then
		touch /etc/persistence/data/fwupgrade_reset_default
	else
		rm -f /etc/persistence/data/fwupgrade_reset_default
	fi
	echo "[UPGRADE] reboot to upgrade firmware..." > /dev/console
fi

### After upgrade
json set firmware status=upgradeSuccess
rm -f /tmp/$FILE_NAME
rm -f /tmp/upgrading_firmware/last_time #release lock

[ "$FROM_WEB" = "1" ] || {
	### Reset default
	if [ "$RESET_DEFAULT" = "1" ]
	then
		echo "Firmware Update: Configuration will be reset to default values when upgrade complete."
		rm -f /etc/persistence/config/*
		rm -rf /etc/persistence/checksum/config
		rm -f /etc/passwd
		rm -f /etc/group
		rm -f /etc/passwd_md5
		rm -f /etc/persistence/data/rev
		rm -f /etc/ucarp/revision
		cp -f /etc/data-default/passwd /etc/persistence/data/passwd
		cp -f /etc/data-default/group /etc/persistence/data/group
		cp -f /etc/data-default/passwd_md5 /etc/persistence/data/passwd_md5
		sync
		sleep 1
		echo 1 > /proc/sys/vm/drop_caches
	fi
	### Reboot
	echo "Firmware Update: Rebooting..."
	reboot
}
