#!/bin/sh

# fiasco-image-update: schedule FIASCO images for flashing
# For every image that contains bits of cmt firmware, stage it
# for later (post-reboot or whatnot) flashing; for every image
# that does NOT contain cmt, proceed to flashing immediately.

# Scheduled updates are to be stored here:
STAGING_DIR=/var/lib/softupd/staging

# Command to actually flash images
CMD_DO_FLASH="/usr/bin/flasher --local -f -F"
# Command to used to obtain list of FIASCO image contents
CMD_FLASHER_LIST="/usr/bin/flasher -F"
# Command to show kernel version string from zImage
CMD_ZIMAGE_GET_VERSION="/usr/bin/zimage-get-version"
# Command to ask user for flashing kernel
CMD_CONFIRM="/usr/bin/run-standalone.sh /usr/bin/maemo-confirm-text"

# Temporary file for kernel confirm question
CONFIRM_FILE="/var/tmp/confirm-kernel"
# Temporary file for unpacking new kernel image
ZIMAGE_FILE="/var/tmp/zImage"
# MTD kernel device
MTD_KERNEL="/dev/mtd3ro"

# set -e

usage() {
	cat<<FIASCO
Usage:
	$(basename $0) [-h][-v] IMAGE [IMAGE] ...
FIASCO
}

say() {
	if [ -n "$verbose" ]; then
		echo "$*"
	fi
}

stage_one_image() {
	__image="$1"
	__path="$STAGING_DIR/$(basename $__image)"

	if [ -e "$__path" ]; then
		echo "Warning: $__path already exists;"
		echo "which means $__image was already scheduled for flashing once."
		rm -f "$__path"
	fi

	ln -sf "$__image" "$__path"
}

# In case staging directory is not a directory
if [ -e "$STAGING_DIR" -a ! -d "$STAGING_DIR" ]; then
	rm -rf "$STAGING_DIR"
fi

if [ ! -d "$STAGING_DIR" ]; then
	mkdir -p "$STAGING_DIR"
fi

# process command line arguments
while [ -n "$1" ]; do
	case "$1" in
		-h)
			usage
			exit 0
			;;
		-v)
			verbose=1
			;;
		-*)
			echo "More options to come"
			usage
			exit 1
			;;
		*)
			if [ -z "$images" ]; then
				images="$1"
			else
				images="$images $1"
			fi
			;;
	esac
	shift
done

if [ -z "$images" ]; then
	echo "Kindly supply at least one image. Thank you."
	usage
	exit 1
fi

# process images
for i in $images; do
	# basic sanity checks
	if [ "${i#/}" = "$i" ]; then
		echo "$i is not an absolute path, skipping"
		continue
	fi

	if [ ! -e "$i" ]; then
		echo "$i does not exist, skipping"
		continue
	fi

	say "Processing image: $i"

	# Check the image to be a valid FIASCO
	if $CMD_FLASHER_LIST "$i" 2>&1 | grep "^Invalid FIASCO file header" >/dev/null; then
		echo "   -> not a valid FIASCO image, skipping"
		continue
	fi

	# Check for CMT content
	if $CMD_FLASHER_LIST "$i" 2>/dev/null | grep "^Image 'cmt-" >/dev/null; then
		say "   -> contains cmt, scheduling for later flashing"
		stage_one_image $i
	else
		say "   -> doesn't contain cmt, flashing right away"
		if [ -z "$images_to_flash" ]; then
			images_to_flash="$i"
		else
			images_to_flash="$images_to_flash $i"
		fi
	fi
done

if [ -n "$images_to_flash" ]; then
	# we have to make sure the proper version of softupd is running
	# before calling flasher
	initctl stop softupd

	/usr/sbin/softupd --local --standalone -v -s &
	su_pid=$!
	sleep 1

	for i in $images_to_flash; do
		# Check for kernel flashing
		if $CMD_FLASHER_LIST "$i" 2>/dev/null | grep "^Image 'kernel'" >/dev/null; then
			rm -f $ZIMAGE_FILE
			$CMD_FLASHER_LIST "$i" -u/var/tmp >/dev/null
			old_ver="$($CMD_ZIMAGE_GET_VERSION $MTD_KERNEL)"
			new_ver="$($CMD_ZIMAGE_GET_VERSION $ZIMAGE_FILE)"

			# Check if old image does not have u-boot version string
			if [ -z "$old_ver" ]; then
				old_ver="$(cat $MTD_KERNEL | tr '\000\001\002\003\004\005\006\007' '\n' | sed -n 's/.*U-Boot \(.*\) (.* - .*).*/U-Boot \1/p' | head -1)"
			fi

			# Check if new image does not have u-boot version string
			if [ -z "$new_ver" ]; then
				new_ver="$(cat $ZIMAGE_FILE | tr '\000\001\002\003\004\005\006\007' '\n' | sed -n 's/.*U-Boot \(.*\) (.* - .*).*/U-Boot \1/p' | head -1)"
			fi

			# Check if new fiasco image does not have version string
			if [ -z "$new_ver" ]; then
				new_ver=$($CMD_FLASHER_LIST "$i" 2>/dev/null | grep -A 1 "^Image 'kernel'" | sed -n 's/.*Version //p' | head -1)
			fi

			rm -f $ZIMAGE_FILE

			# Get "base" version string for comparing
			new_ver_sim="$(echo $new_ver | sed 's/^\([^-]*-[^0-9]*\).*/\1/')"
			old_ver_sim="$(echo $old_ver | sed 's/^\([^-]*-[^0-9]*\).*/\1/')"

			# Show unknown
			if [ -z "$old_ver" ]; then
				old_ver="(unknown)"
			fi

			# Show unknown
			if [ -z "$new_ver" ]; then
				new_ver="(unknown)"
			fi

			echo "Old kernel version: $old_ver"
			echo "New kernel version: $new_ver"

			# If version strings of zImage in mtd and in fiasco image are not similar, then ask user for flashing new version
			# Also ask if version strings are empty
			if [ -z "$old_ver_sim" ] || [ -z "$new_ver_sim" ] || [ "$old_ver_sim" != "$new_ver_sim" ]; then
				rm -f $CONFIRM_FILE
				echo "You are going to flash new kernel image into device NAND memory." >> $CONFIRM_FILE
				echo "But new version string of kernel image is not similar to old." >> $CONFIRM_FILE
				echo "Do you really want to flash this new kernel image?" >> $CONFIRM_FILE
				echo "" >> $CONFIRM_FILE
				echo "Old kernel version: $old_ver" >> $CONFIRM_FILE
				echo "New kernel version: $new_ver" >> $CONFIRM_FILE

				echo "Confirm information text on screen"
				# If X Display is not accessible or user confirmed GUI message, flash kernel
				if [ -z "$DISPLAY" ] || $CMD_CONFIRM "Flash new kernel image" $CONFIRM_FILE; then
					skip=0
				else
					skip=1
				fi

				rm -f $CONFIRM_FILE

				if [ "$skip" = "1" ]; then
					rm -f $i
					continue
				fi
			fi
		fi

		$CMD_DO_FLASH $i || \
			( echo "Flashing $i failed" && kill $su_pid; exit 1 )
		rm -f $i
	done

	kill $su_pid || echo "Problem: softupd died too soon"
	wait $su_pid
fi

