#!/bin/sh

# Created by jiaqiang.ye@lnxall.com
# Simpile firmware upgrade for LNXALL packages
# 2023/07/18

TAGINST=/tmp/.elf-pkg-installed
export PATH=/opt/lnxall_app/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin

FWFILE=''
KEEP_CFGS=1
WAN_MACADDR="$(uci get network.wan.macaddr 2>/dev/null)"

check_system() {
	if [ "$(uname -m)" != "armv7l" ] ; then
		echo "Error, not ARM gateway, cannot install lnxall_app" 1>&2
		return 1
	fi

	if [ -z "$(cat /proc/device-tree/model | tr -d '\0' | grep -a -i -e WooLink5F8280_C)" ] ; then
		echo "Error, not iMX6ULL gateway, cannot install lnxall_app" 1>&2
		return 2
	fi
	return 0
}

check_args() {
	FWFILE="$1"
	if [ "${FWFILE}" = "-n" ] ; then
		KEEP_CFGS=0
		FWFILE="$2"
	fi

	if [ -z "${FWFILE}" ] ; then
		echo "Error, Lnxall package firmware not specified" 1>&2
		return 1
	fi

	if [ ! -f "${FWFILE}" ] ; then
		echo "Error, Lnxall package firmware not found: '${FWFILE}'" 1>&2
		return 2
	fi
	return 0
}

check_md5sum() {
	local file="$1"
	local md5="$2"
	if [ -z "${md5}" ] ; then
		echo "Error, expected MD5SUM not specified for '${file}'" 1>&2
		return 1
	fi

	local md5val="$(md5sum ${file} 2>/dev/null | awk '{print $1}')"
	if [ "${md5val}" != "${md5}" ] ; then
		echo "Error, invalid MD5SUM: '${md5val}', expected: '${md5}'" 1>&2
		return 2
	fi

	echo "LNXALL package upgrade firmware MD5SUM check OK."
	return 0
}

# intermediate variable for function `get_md5sum
MD5SUM_VAL=''
get_md5sum() {
	local file="$1"
	if [ ! -f "${file}" ] ; then
		MD5SUM_VAL=''
		return 1
	fi

	local md5val="$(md5sum ${file} 2>/dev/null | awk '{print $1}')"
	if [ -z "${md5val}" ] ; then
		MD5SUM_VAL=''
		return 2
	fi
	MD5SUM_VAL="${md5val}"
	return 0
}

inst_systemd() {
	local svrname="$1"
	local destdir="/usr/lib/systemd/system"

	get_md5sum "platspec/${svrname}"
	local md5_0="${MD5SUM_VAL}"
	if [ -z "${md5_0}" ] ; then
		echo "Installing '${svrname}'..."
		cp -v -f "platspec/${svrname}" "${destdir}/${svrname}" && \
			systemctl enable "${svrname}" && systemctl start "${svrname}"
		return $?
	fi

	get_md5sum "${destdir}/${svrname}"
	local md5_1="${MD5SUM_VAL}"
	if [ "${md5_0}" != "${md5_1}" ] ; then
		echo "Installing '${svrname}'..."
		if cp -v -f "platspec/${svrname}" "${destdir}/" ; then
			systemctl daemon-reload
			systemctl enable "${svrname}"
			systemctl start "${svrname}"
		fi
	fi
	return 0
}

# There are some debian services that should be disabled
disable_svrs() {
	# disable strongswan service, because it removes br-lan interface
	systemctl stop strongswan >/dev/null 2>/dev/null
	systemctl disable strongswan >/dev/null 2>/dev/null

	# disable hostapd service, as we use lnxhostapd
	systemctl stop hostapd >/dev/null 2>/dev/null
	systemctl disable hostapd >/dev/null 2>/dev/null

	return 0
}

frpc_install() {
	local APPDIR="$1"
	[ ! -s '/etc/frpc.ini' ] && cp -v -f "${APPDIR}/app/config/frpc.ini" /etc/frpc.ini
	[ ${KEEP_CFGS} -eq 0 ] && cp -v -f "${APPDIR}/app/config/frpc.ini" /etc/frpc.ini
	diff -q /usr/bin/frpc-sn "${APPDIR}/platspec/frpc-sn" >/dev/null 2>/dev/null
	[ $? -ne 0 ] && cp -v -f "${APPDIR}/platspec/frpc-sn" /usr/bin/frpc-sn
	cp -v -f "${APPDIR}/platspec/frpc" /usr/bin/frpc
	inst_systemd 'frpc.service'
}

post_install() {
	local profile='/root/.profile'
	if [ ! -f "${profile}" ] ; then
		rm -rf "${profile}"
		# create ${profile}
		echo '#!/bin/sh' > "${profile}"
	fi

	local APPDIR='/opt/lnxall_app'
	local BATH='/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin'
	# setup new PATH environment variable
	export PATH="${APPDIR}/bin:${APPDIR}/sbin:${BATH}"

	# update ${profile} if necessary
	if [ -z "$(grep -e ${APPDIR} ${profile})" ] ; then
		echo "Updating '${profile}'..."
		echo "export PATH=${PATH}" >> "${profile}"
	fi

	disable_svrs # disable unused services
	cd "${APPDIR}" || return 1
	# install XXX.service for systemd based system
	inst_systemd 'linit.service'

	# install rathole configuration file
	if [ ! -s '/etc/facini/rathole.toml' ] ; then
		mkdir -p '/etc/facini'
		cp -v -f './app/config/rathole.toml' '/etc/facini/rathole.toml'
	fi
	inst_systemd 'ratholec.service'
	frpc_install "${APPDIR}"
	inst_systemd 'emud.service'

	# fix iMX6UL mmc1 hang
	cp -f -v /opt/lnxall_app/bin/imx6ul_mmc1_watch /usr/local/bin/
	inst_systemd mmc1watch.service

	# symlink for ssd_format.sh on RK3568
	if [ ! -x '/usr/bin/ssd_format.sh' ] ; then
		[ -e "${APPDIR}/bin/ssd_format.sh" ] && rm -rf  \
			'/usr/bin/ssd_format.sh' && ln -sv "${APPDIR}/bin/ssd_format.sh" '/usr/bin/'
	fi

	# for compatibility with openwrt, create /etc/config symlink
	[ ! -e "${APPDIR}/etc/config" ] && mkdir -p "${APPDIR}/etc/config"
	[ ! -e '/etc/config' ] && ln -sv "${APPDIR}/etc/config" '/etc/config'

	# install bdhcpd.service, but do not enable it:
	diff -q "${APPDIR}/platspec/bdhcpd.service" '/usr/lib/systemd/system/bdhcpd.service' 2>/dev/null
	if [ $? -ne 0 ] ; then
		cp -v -f "${APPDIR}/platspec/bdhcpd.service" /usr/lib/systemd/system/
		systemctl daemon-reload
	fi

	# install lnxhostapd.service, but do not enable it:
	diff -rq "${APPDIR}/platspec/lnxhostapd.service" '/usr/lib/systemd/system/lnxhostapd.service' 2>/dev/null
	if [ $? -ne 0 ] ; then
		cp -v -f "${APPDIR}/platspec/lnxhostapd.service" '/usr/lib/systemd/system/lnxhostapd.service'
		systemctl daemon-reload
	fi

	# symlink for factory script
	if [ ! -x '/usr/bin/factory' ] ; then
		[ -e "${APPDIR}/bin/factory" ] && rm -rf \
			'/usr/bin/factory' && ln -sv "${APPDIR}/bin/factory" '/usr/bin/'
	fi

	# symlink for diag script
	if [ ! -x '/usr/bin/diag.sh' ] ; then
		[ -e "${APPDIR}/bin/diag.sh" ] && rm -rf \
			'/usr/bin/diag.sh' && ln -sv "${APPDIR}/bin/diag.sh" '/usr/bin/'
	fi

	# initialize network and wireless configuration
	if [ ! -e '/etc/config/wireless' ] ; then
		[ -e "${APPDIR}/platspec/etc-config-wireless" ] && \
			cp -v "${APPDIR}/platspec/etc-config-wireless" '/etc/config/wireless'
	fi
	if [ ! -s '/etc/config/network' ] ; then
		if [ -e "${APPDIR}/platspec/etc-config-network" ] ; then
			cp -v -f "${APPDIR}/platspec/etc-config-network" '/etc/config/network'
			if [ -n "${WAN_MACADDR}" ] ; then
				uci set "network.wan.macaddr=${WAN_MACADDR}"
				uci commit network
			fi
			nothup /bin/sh -c 'sleep 5 && exec netuci'
		fi
	fi

	sync # OK, flush filesystem before return
	return 0
}

fw_install() {
	local fw_file="$1"
	mkdir -p /opt && cd /opt
	[ $? -ne 0 ] && return 1
	touch ${TAGINST}

	# stop Lnxall INITialize service, twice
	echo "Stopping Lnxall services..."
	systemctl stop linit.service >/dev/null 2>/dev/null ; sleep 1
	systemctl stop linit.service >/dev/null 2>/dev/null
	systemctl stop emud.service

	local backups='lnxall_backup.tar'
	rm -rf ${backups} # remove backup settings
	if [ ${KEEP_CFGS} -eq 1 ] ; then
		echo "Backing up lnxall configs..."
		local KEEPDIRS='lnxall_app/app/config' # /app/config always exists
		[ -e 'lnxall_app/app/node' ] && KEEPDIRS="${KEEPDIRS} lnxall_app/app/node"
		[ -e 'lnxall_app/app/adapter' ] && KEEPDIRS="${KEEPDIRS} lnxall_app/app/adapter"
		[ -e 'lnxall_app/app/global/template' ] && KEEPDIRS="${KEEPDIRS} lnxall_app/app/global/template"
		[ -e 'lnxall_app/app/template' ] && [ ! -L 'lnxall_app/app/template' ] && KEEPDIRS="${KEEPDIRS} lnxall_app/app/template"
		[ -e 'lnxall_app/etc/config' ] && KEEPDIRS="${KEEPDIRS} lnxall_app/etc/config"
		[ -e 'lnxall_app/lib/dyiot/appdis' ] && KEEPDIRS="${KEEPDIRS} lnxall_app/lib/dyiot/appdis"
		[ -d 'lnxall_app' ] && tar -cvf "${backups}" ${KEEPDIRS}

		# NOTE: in /opt directory, backup database directory:
		rm -rf db_backup
		if [ -e 'lnxall_app/app/database' ] ; then
			mv -vf 'lnxall_app/app/database' db_backup
		fi
	fi

	# create temporary directory and extract everything in it
	rm -rf .tmpextract/*
	mkdir -p .tmpextract
	cd .tmpextract || return 2
	echo "Extracting from lnxall package '${fw_file}'..."
	cat "${fw_file}" | xz -d -c | tar -x -f - # extract only once
	if [ $? -ne 0 ] ; then
		rm -rf ./* ; cd ..
		echo "Error, failed to extract \"${fw_file}\"" | tee -a ${TAGINST}
		return 3
	fi

	echo "$(date): lnxall_app extracted" | tee -a ${TAGINST}
	# remove /opt/lnxall_app
	rm -rf ../lnxall_app
	rm -rf ../lnxall_app # remove twice
	mv -v -f * ../
	cd .. # go back to upper directory

	rm -rf "${fw_file}" # remove extracted firmware
	if [ ${KEEP_CFGS} -eq 1 ] ; then
		echo "Restoring backups..."
		[ -e "${backups}" ] && tar -x -v -f "${backups}"
		if [ -e 'db_backup' ] ; then
			if [ -L 'db_backup' ] ; then
				mv -vf db_backup lnxall_app/app/database
			else
				mkdir -vp lnxall_app/app/database
				mv -vf db_backup/* lnxall_app/app/database/
				rm -vrf db_backup
			fi
		fi
		rm -rf "${backups}"
	fi

	sync ; post_install
	# Blink LED if no GWSN found:
	nothup lua /opt/lnxall_app/bin/elf-update-blink-no-gwsn.lua
	mv /opt/lnxall_app/bin/lnxall-inst.sh /usr/bin/
	echo "Restarting Lnxall services..."
	systemctl restart linit.service
	systemctl restart emud.service
	return $?
}

umask 022
check_system || exit 1
check_args "$@" || exit 2
check_md5sum "${FWFILE}" "${FW_MD5SUM}" || exit 3
fw_install "${FWFILE}"
exit $?
