#!/bin/sh
# Copyright (C) 2006-2010 OpenWrt.org
# Copyright (C) 2010 Vertical Communications


# When we failed  mount /data, the whole mtd partition will be automatically erased by "mtd erase overlay"
# thus we lose all config files. here we try to save the day
do_data_mount_fail_recover() {
	local rec_mtd_name="cfg_bak"

	[ -f /tmp/need_config_recovery ] || return 0
	rm -f /tmp/need_config_recovery

	rec_mtd=$(find_mtd_part "$rec_mtd_name")
	[ -z "$rec_mtd" ] && return 0

	dd if="$rec_mtd" of=/tmp/head.bin bs=4 count=1
	head=`hexdump -e '1/4 "%.6x"' /tmp/head.bin`
	[ "$head" = "088b1f" ] || return 0

	#found a valid gzip header
	echo "Data fail etc recover..."
	dd if="$rec_mtd" of=/tmp/rec.tar.gz bs=2048
	mkdir -p /tmp/tmpconfig
	tar -xzf /tmp/rec.tar.gz -C /tmp/tmpconfig
	[ "$?" = "0" ] || {
		echo "Fail to extract backup config"
		return 0
	}
	cp -rf /tmp/tmpconfig/etc/config/* /etc/config/
	rm -rf /tmp/tmpconfig/etc/config
}

# Check uci config files in /etc/config/. Corrupted uci configs could cause uci deadloop
# Recovery sequence:
# 1. from mtd cfg_bak partition [TBD]
# 2. from the other system's config (/data/etc_bak)
# 3. from rootfs
do_uci_config_integrity_check() {
	for file in `find /data/etc/config -type f`
	do
		cat $file > /dev/null
		[ "$?" = "0" ] && continue

		[ -d /data/etc_bak ] && {
			bakfile=`echo $file | sed "s/\/data\/etc/\/data\/etc_bak/g"`
			[ -f "$bakfile" ] && {
				rm -f $file
				cp $bakfile $file
				echo Recover $file from the other system
				continue
			}
		}

		rootfs_file=`echo $file | sed "s/\/data\/etc/\/etc/g"`
		[ -f "$rootfs_file" ] && {
			rm -f $file
			cp $rootfs_file $file
			echo Recover $file from rootfs
			continue
		}

		# Can't recover. Remove the file to prevent trouble.
		rm -f $file
	done
}


do_recovery_config() {
	if [ ! -f /etc/remove.conf ]
	then
		echo " ************* WARNING *******************"
		echo " ***** /rom/etc/remove.conf no exist and try to rsync files ****"
	else
		echo " *****ota: remove files in /etc/remove.conf *****"
		cat /etc/remove.conf | xargs rm -rf
	fi

	echo N | cp -ri /etc/* /data/etc 2>/dev/null
}

# Process /etc under different scenario
# Return 1 if OTA scenario. otherwise return 0
process_etc() {
	# for: 1, ota; 2, format disk; 3, downgrade

	mkdir -p /data/etc
        flag_name=`uci get misc.mount_bind_etc.flag_name`
	flg_ota=`nvram get flag_ota_reboot`
	flg_format=`nvram get $flag_name`
	curr_os=`nvram get flag_boot_rootfs`
	[ -z "$curr_os" ] && curr_os=0
	bkup_os=$((1-$curr_os))

	if [ "$flg_format" = "1" ]; then
		# /data is fresh formated. simply make a copy of /etc
		rm -rf /data/etc
		cp -prf /etc /data/etc
		nvram unset $flag_name
		nvram unset flag_recover_config
		nvram commit
		return 0
	fi

	# check if we are with correct etc files
	if [ "$flg_ota" = "0" ]; then
		flg_try_sys1=`nvram get flag_try_sys1_failed`
		flg_try_sys2=`nvram get flag_try_sys2_failed`

		# if any fail flag is set, we might need etc recovery
		if [ "$flg_try_sys1" = "1" -o "$flg_try_sys2" = "1" ]; then
			echo "System fail flag set. Do etc recovery"
		else
			return 0
		fi

		if [ ! -d /data/etc_bak ]; then
			echo " WARNING: No etc_bak folder"
			do_recovery_config
			return 0
		fi

		if [ `ls /data/etc_bak | wc -l` -eq 0 ]; then
			echo " ERROR: Empty backup etc"
			rm -rf /data/etc_bak
			do_recovery_config
			return 0
		fi

		if [ -f "/data/etc_bak/with_os_0" -a -f "/data/etc_bak/with_os_1" ]; then
			# something is wrong. assume etc bak is corrupt
			echo " ERROR: Confusing with etc OS flags"
			rm -rf /data/etc_bak
			do_recovery_config
			return 0
		fi

		# if backup etc OS number match with current OS number, switch etc
		if [ -f /data/etc_bak/with_os_"$curr_os" ]; then
			echo " Use backup etc"
			mv /data/etc /data/etc_tmp
			mv /data/etc_bak /data/etc
			mv /data/etc_tmp /data/etc_bak
			rm -f /data/etc_bak/with_os*
			touch /data/etc_bak/with_os_"$bkup_os"
		fi
		return 0
	fi

	if [ "$flg_ota" = "1" ]; then
		/usr/sbin/config_pre_ota.sh

		do_recovery_config
		return 1
	fi

	return 0
}

do_mount_bind_etc() {

	process_etc
	post_ota="$?"

	#replace files that size 0 in /data/etc
	cd /data/etc
	find . -size 0 | while read line
	do
		if [ -s /etc/$line -a -f /etc/$line ]; then
			echo "/etc damaged, recovering /etc/$line"
			cp -arf /etc/$line /data/etc/$line
		fi
	done
	cd /
	sync

	# Do uci conf integrity checks before we mount.bind /etc
	do_uci_config_integrity_check

	mount --bind /data/etc /etc

	rm -f /etc/with_os*
	touch /etc/with_os_"$curr_os"

	do_data_mount_fail_recover

	if [ "$post_ota" = "1" ] ; then
		/usr/sbin/config_post_ota.sh
	fi

	[ -s /tmp/.uci.disk ] && uci import -f /tmp/.uci.disk && rm -f /tmp/.uci.disk
	[ -f /etc/sysdisk ] && cp -f /etc/sysdisk /tmp/sysdisk

}

boot_hook_add preinit_main do_mount_bind_etc

