#!/bin/sh

CURR_DIR="$(dirname $0)"
LINUX_UPDATE_INSTRUCTION_PATH="$CURR_DIR/insp_LinuxUpdate.txt"
RECOVERY_PATH="/mnt/recovery"
MAX_RETRIES=5
UPDATE_OUTPUT_LOCATION="/mnt/sdcard/"

check_partition_sum () {

	RETRY_COUNT=0
	IMG_PATH=$1
	PART_PATH=$2
	SUCCESS=false

	while [ "$RETRY_COUNT" -lt "$MAX_RETRIES" ]; do

		img_sum_output=$(sha1sum "$IMG_PATH")
		exp_sum=$(echo "$img_sum_output" | awk '{print $1}')
		part_sum_output=$(sha1sum "$PART_PATH")
		part_sum=$(echo "$part_sum_output" | awk '{print $1}')
	
		if [ "$exp_sum" == "$part_sum" ];
		then
			echo "GOOD partition checksum $part_sum_output when checking against $img_sum_output" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt
			SUCCESS=true
			break
		else
			echo "Bad partition checksum $part_sum_output when checking against $img_sum_output" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt
			RETRY_COUNT=$((RETRY_COUNT + 1))
			dd if=$IMG_PATH of=$PART_PATH conv=fsync
			sync
		fi
	done
	sync
	echo $SUCCESS
}

check_file_sum () {

	RETRY_COUNT=0
	FILE_PATH=$1
	DEST_PATH=$2
	SUCCESS=false

	while [ "$RETRY_COUNT" -lt "$MAX_RETRIES" ]; do

		file_sum_output=$(sha1sum "$FILE_PATH")
		exp_sum=$(echo "$file_sum_output" | awk '{print $1}')
		dest_sum_output=$(sha1sum "$DEST_PATH")
		dest_sum=$(echo "$dest_sum_output" | awk '{print $1}')
	
		if [ "$exp_sum" == "$dest_sum" ];
		then
			echo "GOOD file checksum $dest_sum_output when checking against $file_sum_output" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt	
			SUCCESS=true
			break
		else
			echo "Bad file checksum $dest_sum_output when checking against $file_sum_output" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt	
			RETRY_COUNT=$((RETRY_COUNT + 1))
			cp $FILE_PATH $DEST_PATH
			sync
		fi
	done
	sync
	echo $SUCCESS
}

check_dir_sum () {
	RETRY_COUNT=0
	DIR_PATH=$1
	DEST_PATH=$2
	SUCCESS=false

	while [ "$RETRY_COUNT" -lt "$MAX_RETRIES" ]; do

		# Ensure both directory outputs are sorted in the same way so its a 1:1 compare
		file_sum_output=$(find "$DIR_PATH" -type f | awk -F/ '{print $NF, $0}' | sort | awk '{print $2}' | xargs sha1sum)
		exp_sum=$(find "$DIR_PATH" -type f | awk -F/ '{print $NF, $0}' | sort | awk '{print $2}' | xargs sha1sum | awk '{print $1}')
		dest_sum_output=$(find "$DEST_PATH" -type f | awk -F/ '{print $NF, $0}' | sort | awk '{print $2}' | xargs sha1sum)
		dest_sum=$(find "$DEST_PATH" -type f | awk -F/ '{print $NF, $0}' | sort | awk '{print $2}' | xargs sha1sum | awk '{print $1}')

		if [ "$exp_sum" == "$dest_sum" ];
		then
			echo "GOOD directory checksum $dest_sum_output when checking against $file_sum_output" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt	
			SUCCESS=true
			break
		else
			echo "Bad directory checksum $dest_sum_output when checking against $file_sum_output" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt	
			RETRY_COUNT=$((RETRY_COUNT + 1))
			rm -rf $DEST_PATH
			mkdir $DEST_PATH
			cp -rf $DIR_PATH/* $DEST_PATH
			sync
		fi
	done
	sync
	echo $SUCCESS
}

checkPostUpdate () {
	sync
	sync
	IS_UPDATE_SUCCESSFUL=true
	
	while IFS= read -r instruction || [[ -n "$instruction" ]]; do
	
		operation=$(echo "$instruction" | awk -F ',' '{print $1}')
		filename=$(echo "$instruction" | awk -F ',' '{print $2}')
		curr_file_path="$CURR_DIR/$filename"
		destination=$(echo "$instruction" | awk -F ',' '{print $3}')
		source=""
	
		# avoid checking for appdata. Contains databases that change always resulting in a different checksum
		# avoid checking for kernel. The checksum is always different
		if [[ "$operation" == "IMG" && "$filename" != "appdata.ext4" && "$filename" != "zImage" ]]; then
			if [[ "$(check_partition_sum $curr_file_path $destination)" == "false" ]]; then
				echo "$filename couldn't be flashed properly, forced to reboot and recover" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt
				IS_UPDATE_SUCCESSFUL=false
			fi
		elif [[ "$operation" == "ADD" ]]; then
			if [[ "$(check_file_sum $curr_file_path "$destination/$filename")" == "false" ]]; then
				echo "$filename couldn't be flashed properly, forced to reboot and recover" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt
				IS_UPDATE_SUCCESSFUL=false
			fi
		elif [ "$operation" = "SCRIPT" ]; then # its possible files would be included with the cp command, check for that
			cmd="$destination"
			operation=$(echo "$cmd" | awk -F ' ' '{print $1}')
			arg1=$(echo "$cmd" | awk -F ' ' '{print $2}')
			arg2=$(echo "$cmd" | awk -F ' ' '{print $3}')
			arg3=$(echo "$cmd" | awk -F ' ' '{print $4}')
			
			if [ "$operation" == "cp" ]; then
				if [[ "${arg1:0:1}" == "-" ]]; then
					source="$arg2"
					filename=$(echo "$arg2" | awk -F '/' '{print $4}')
					destination="$arg3"
				else
					source="$arg1"
					filename=$(echo "$arg1" | awk -F '/' '{print $4}')
					destination="$arg2"
				fi

				curr_dir_path="$CURR_DIR/$filename"

				# if the source file location is not within the update then
				# its simply just an updating instruction so ignore
				if echo "$source" | grep -q "/tmp/update"; then
					if [[ "$(check_dir_sum $curr_dir_path "$destination$filename")" == "false" ]]; then
						echo "$filename directory couldn't be flashed properly, forced to reboot and recover" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt
						IS_UPDATE_SUCCESSFUL=false
					fi
				fi
			fi
		fi
	
	done < $LINUX_UPDATE_INSTRUCTION_PATH
	
	# update success flag only applies to devices with a recovery partition
	# devices without a recovery partition will be unrecoverable upon a failed update
	if [[ "$IS_UPDATE_SUCCESSFUL" == "true" ]]; then
		# update is successful so copy the application partition to be flashed on next boot
		cp -f "$CURR_DIR/application.ext4" /mnt/userdata
		if [[ -d "$RECOVERY_PATH"  ]]; then
			cp $LINUX_UPDATE_INSTRUCTION_PATH $RECOVERY_PATH
			touch "$RECOVERY_PATH/updateSuccessful.flag"
		fi
	fi
}

checkPreUpdate () {

	CURR_DIR="$(dirname $0)"
	FILES_SUMS_PATH="$CURR_DIR/fileChecksums.sha1"
	
	echo "=====================================================" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt	

	while IFS= read -r file_sum || [[ -n "$file_sum" ]]; do
	
		exp_sum=$(echo "$file_sum" | awk '{print $1}')
		filename=$(echo "$file_sum" | awk '{print $2}')
		dest_sum_output=$(sha1sum "$CURR_DIR/$filename")
		dest_sum=$(echo "$dest_sum_output" | awk '{print $1}')
	
	
		if [ "$exp_sum" == "$dest_sum" ];
		then
			echo "GOOD transfer checksum $dest_sum_output when checking against $file_sum" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt	
		else
			echo "Bad transfer checksum $dest_sum_output when checking against $file_sum" >> "$UPDATE_OUTPUT_LOCATION"update_output.txt	
			# Abort the update, it shouldn't proceed with corrupted files
			reboot
		fi
	
	done < $FILES_SUMS_PATH
}


if [[ "$1" == "pre" ]]; then
	checkPreUpdate
elif [[ "$1" == "post" ]]; then
	checkPostUpdate
fi