#!/bin/sh
#
# OpenIPC.org | v.20220222
#

set -e

echo_c() {
	[ -z "$HASERLVER" ] && t="\e[1;$1m$2\e[0m" || t="$2"
	echo -e "$t"
}

die() {
	echo_c 31 "$1 Aborting."
	reboot_system
}

check_soc() {
	[ "$skip_soc" -eq 1 ] && echo "Skip SoC validation" && return 0
	[ "$1" = "$soc" ] && echo "SoC OK" && return 0
	die "Wrong SoC!"
}

compare_versions() {
	[ "$skip_ver" -eq 1 ] && echo "Skip version checking" && return 1
	[ "$1" = "$2" ] && echo_c 32 "Same version, nothing to update" && return 0
	echo_c 32 "New version, going to update" && return 1
}

do_update_kernel() {
	x=$1
	[ -z "$x" ] && x="/tmp/uImage.$soc"
	echo_c 33 "\nKernel"
	echo "Update kernel from $x"
	[ ! -f "$x" ] && die "File $x not found"
	check_soc "$(od -j 32 -N 32 -S 1 -A n "$x" | cut -d- -f3)"
	compare_versions "$kernel_version" "$(get_kernel_version "$x")" && return 0
	flashcp -v "$x" "$kernel_device"
	echo_c 32 "Kernel updated to $(get_kernel_version "$kernel_device")"
	unset x
}

do_update_rootfs() {
	x=$1
	[ -z "$x" ] && x="/tmp/rootfs.squashfs.$soc"
	echo_c 33 "\nRootFS"
	echo "Update rootfs from $x"
	[ ! -f "$x" ] && die "File ${x} not found"
	y=/tmp/rootfs
	if mkdir -p "$y" && loop=$(losetup -f) && losetup "$loop" "$x" && mount "$loop" "$y"; then
		check_soc "$(head -1 ${y}/etc/hostname | cut -d- -f2)"
		compare_versions "$system_version" "$(get_system_version "$y")" && return 0
		umount "$y" && rm -rf "$y" && losetup -d "$loop"
	else
		die "Unable to mount $y!"
	fi
	unset y

	flashcp -v "$x" "$(get_device "rootfs")"
	echo_c 32 "RootFS updated to $(get_system_version "")"
	unset x
}


do_wipe_overlay() {
	echo_c 33 "\nOverlayFS"
	echo "Erase overlay partition"
	flash_eraseall -j "$(get_device "rootfs_data")"
}

download_firmware() {
	echo_c 33 "\nFirmware"
	[ -z "$url" ] && url="https://github.com/OpenIPC/firmware/releases/download/latest/openipc.${soc}-br.tgz"
	echo "Download from $url"
	[ -z "$HASERLVER" ] && progress="-#" || progress="-s"
	[ "$(curl -o /dev/null -s -w '%{http_code}\n' "$url")" = "000" ] && die "Check your network!"
	curl --connect-timeout 30 -m 60 -L "$url" ${progress} -o - | gzip -d | tar xf - -C /tmp || die "Cannot retrieve $url"
	if [ "$skip_md5" -eq 0 ]; then
		(cd /tmp && md5sum -s -c *.md5sum) || die "Wrong checksum!"
	fi
}

free_resources() {
	echo_c 97 "\nStop services, unload modules"
	killall majestic crond klogd ntpd rngd syslogd >/dev/null 2>&1 || true
	"load_$vendor" -r >/dev/null 2>&1 || true
}

get_device() {
	echo -n "/dev/$(grep "\"$1\"" /proc/mtd | cut -d: -f1)"
}

get_kernel_version() {
	echo -n "0x$(xxd -l 4 -s 8 -p "$1" | xargs)"
}

get_system_info() {
	vendor=$(ipcinfo --vendor)
	soc=$(fw_printenv -n soc) || die "SoC is not defined in U-Boot environment"
	kernel_device=$(get_device "kernel")
	kernel_version=$(get_kernel_version "$kernel_device")
	system_version=$(get_system_version "")
}

get_system_version() {
	grep "GITHUB_VERSION" "$1/etc/os-release" | head -1 | cut -d= -f2 | sed 's/"//g'
}

print_sysinfo() {
	get_system_info
	echo_c 33 "OpenIPC System Updater"
	echo_c 96 "\nVendor\t$vendor\nSoC\t$soc\nKernel\t$kernel_version\nRootFS\t$system_version"
}

print_usage() {
	echo "
Usage: $0 [options]

  -k			update kernel from online repository
  -r			update rootfs from online repository
      --url=[URL]	custom URL to update from (.tgz format)
      --kernel=[FILE]	update kernel from file (uImage format)
      --rootfs=[FILE]	update rootfs from file (squashfs format)
      --force_md5	do not validate MD5 hash
      --force_soc	do not validate processor
      --force_ver	do not validate release version
      --force_all	do not validate anything
  -n, --wipe_overlay	wipe overlay partition
  -x, --no_reboot	do not reboot after updating
  -h, --help		display this help and exit
"
}

reboot_system() {
	[ "$skip_reboot" -eq 1 ] && echo_c 31 "\nReboot needed!" && exit 1
	echo_c 97 "\nUnconditional reboot"
	reboot -d 1 -f
}

clear_overlay=0
remote_update=0
skip_md5=0
skip_soc=0
skip_ver=0
skip_reboot=0
update_kernel=0
update_rootfs=0

for i in "$@"; do
	case $i in
	--force_all)
		skip_md5=1
		skip_soc=1
		skip_ver=1
		shift
		;;
	--force_md5)
		skip_md5=1
		shift
		;;
	--force_soc)
		skip_soc=1
		shift
		;;
	--force_ver)
		skip_ver=1
		shift
		;;
	-h|--help)
		print_sysinfo
		print_usage
		exit 0
		;;
	-k )
		update_kernel=1
		remote_update=1
		shift
		;;
	--kernel=*)
		update_kernel=1
		kernel_file="${i#*=}"
		shift
		;;
	-n|--wipe_overlay)
		clear_overlay=1
		shift
		;;
	-r)
		update_rootfs=1
		remote_update=1
		shift
		;;
	--rootfs=*)
		update_rootfs=1
		rootfs_file="${i#*=}"
		shift
		;;
	--url=*)
		url="${i#*=}"
		shift
		;;
	-x|--no_reboot)
		skip_reboot=1
		shift
		;;
	*)
		print_sysinfo
		echo_c 97 "\nUnknown option: $1"
		print_usage
		exit 1
		;;
	esac
done

print_sysinfo

[ "$update_kernel" -eq 0 ] && \
[ "$update_rootfs" -eq 0 ] && \
[ "$clear_overlay" -eq 0 ] && \
echo_c 97 "\nTry '$(basename "$0") --help' for options." && \
exit 0

free_resources
[ "$remote_update" -eq 1 ] && download_firmware
[ "$update_kernel" -eq 1 ] && do_update_kernel "$kernel_file"
[ "$update_rootfs" -eq 1 ] && do_update_rootfs "$rootfs_file"
[ "$clear_overlay" -eq 1 ] && do_wipe_overlay
reboot_system