[OpenWrt-Devel] [PATCH 2/2] sysupgrade: NAND: Prefer CONTROL for board, improve robustness

Jeff Kletsky lede at allycomm.com
Thu Oct 24 23:57:53 EDT 2019


From: Jeff Kletsky <git-commits at allycomm.com>

Improve NAND-based sysupgrade for current and future upgrades

nand_upgrade_tar():

  * Use the CONTROL file specific to the running board
    to determine asset directory name in the tar file
    * Check for string `BOARD=board_name` directly rather than
      source-ing to allow for future formats, such as JSON
  * Check that either `kernel` or `root` exists in that directory
  * Fall back to the matching, board-specific directory itself
  * Fall back to legacy behavior of "first in tar t -f"
  * Abort writing if no kernel or root was found

  * Catch error return from nand_upgrade_prepare_ubi() and
    * Do not write kernel
    * Do not write rootfs
    * Call (new) nand_do_upgrade_abort()

nand_upgrade_prepare_ubi():

  * Don't destroy existing file system with zero-length rootfs
    (this error condition previously made the device unbootable)

nand_do_upgrade_abort():

  * Show failure message and error code
  * Give 5 s to read or interrupt

Cleaned up some shellcheck suggestions in areas edited.

Left untouched, as working, even if not supported by dash:
  local root_ubiblk="ubiblock${root_ubivol:3}"

Run-tested-on: EA8300 (NAND), GL-AR750S (NOR kernel, NAND rootfs)

Signed-off-by: Jeff Kletsky <git-commits at allycomm.com>
---
 .../base-files/files/lib/upgrade/common.sh    |   7 +-
 package/base-files/files/lib/upgrade/nand.sh  | 129 ++++++++++++++----
 2 files changed, 108 insertions(+), 28 deletions(-)

diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh
index a986cc0b5c..818376d728 100644
--- a/package/base-files/files/lib/upgrade/common.sh
+++ b/package/base-files/files/lib/upgrade/common.sh
@@ -231,11 +231,16 @@ indicate_upgrade() {
 # $(1): path to image
 # $(2): (optional) pipe command to extract firmware, e.g. dd bs=n skip=m
 default_do_upgrade() {
+	local err
 	sync
 	if [ -n "$UPGRADE_BACKUP" ]; then
 		get_image "$1" "$2" | mtd $MTD_ARGS $MTD_CONFIG_ARGS -j "$UPGRADE_BACKUP" write - "${PART_NAME:-image}"
 	else
 		get_image "$1" "$2" | mtd $MTD_ARGS write - "${PART_NAME:-image}"
 	fi
-	[ $? -ne 0 ] && exit 1
+	err=$?
+	if [ $err -ne 0 ] ; then
+		>&2 echo "ERROR: default_do_upgrade mtd write error: $err"
+		exit 1
+	fi
 }
diff --git a/package/base-files/files/lib/upgrade/nand.sh b/package/base-files/files/lib/upgrade/nand.sh
index e7d7bf8d13..1a28539150 100644
--- a/package/base-files/files/lib/upgrade/nand.sh
+++ b/package/base-files/files/lib/upgrade/nand.sh
@@ -121,6 +121,11 @@ nand_upgrade_prepare_ubi() {
 	local has_kernel="${3:-0}"
 	local has_env="${4:-0}"
 
+	if [ -z "$rootfs_length" ] || [ "$rootfs_length" = 0 ] ; then
+		>&2 echo "ERROR: rootfs_length must be non-zero."
+		return 1
+	fi
+
 	local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
 	if [ ! "$mtdnum" ]; then
 		echo "cannot find ubi mtd partition $CI_UBIPART"
@@ -195,16 +200,6 @@ nand_upgrade_prepare_ubi() {
 	return 0
 }
 
-nand_do_upgrade_success() {
-	local conf_tar="/tmp/sysupgrade.tgz"
-
-	sync
-	[ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
-	echo "sysupgrade successful"
-	umount -a
-	reboot -f
-}
-
 # Flash the UBI image to MTD partition
 nand_upgrade_ubinized() {
 	local ubi_file="$1"
@@ -226,14 +221,18 @@ nand_upgrade_ubinized() {
 	sync
 	ubiformat "${mtddev}" -y -f "${ubi_file}"
 	ubiattach -p "${mtddev}"
+
 	nand_do_upgrade_success
 }
 
 # Write the UBIFS image to UBI volume
 nand_upgrade_ubifs() {
 	local rootfs_length=`(cat $1 | wc -c) 2> /dev/null`
+	local err
 
 	nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
+	err=$?
+	[ "$err" != 0 ] && nand_do_upgrade_abort "nand_upgrade_prepare_ubi returned '$err'"
 
 	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
 	local root_ubivol="$(nand_find_volume $ubidev $CI_ROOTPART)"
@@ -242,36 +241,85 @@ nand_upgrade_ubifs() {
 	nand_do_upgrade_success
 }
 
+nand_upgrade_tar_dir_has_assets() {
+	local tar_file="$1"
+	local board_dir="$2"
+
+	local asset
+
+	[ -z "$tar_file" ] && return 1
+
+	for asset in "${board_dir}/root" "${board_dir}/kernel" ; do
+		tar t -f "$tar_file" "$asset" | grep -Fxq "$asset" && return 0
+	done
+	return 1
+}
+
 nand_upgrade_tar() {
 	local tar_file="$1"
 	local kernel_mtd="$(find_mtd_index $CI_KERNPART)"
 
-	local board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
-	board_dir=${board_dir%/}
+	local dts_board
+	local control_file
+	local board_dir
+	local err
+
+	dts_board="$(board_name)"
+	echo "$dts_board" | grep -Fq , && \
+		dts_board="${dts_board%%,*}_${dts_board#*,}"
+
+	control_file="sysupgrade-${dts_board}/CONTROL"
+
+	# Accomodate future CONTROL formats, as long as BOARD=board_name present
+
+	board_dir="sysupgrade-$(tar x -O -f "$tar_file" "$control_file" | \
+		grep -m 1 -o -E "\bBOARD=[^[:space:]'\"]+" | \
+		cut -d = -f 2)"
+
+	if [ "$board_dir" = "sysupgrade-" ] ; then
+		>&2 echo "Unable to determine directory from '${control_file}'."
+		board_dir="sysupgrade-${dts_board}"
+	fi
+
+	if ! nand_upgrade_tar_dir_has_assets "$tar_file" "$board_dir" ; then
+		>&2 echo "No assets found for '${board_dir}/', falling back to legacy method."
+		board_dir=$(tar t -f "$tar_file" | grep -m 1 '^sysupgrade-.*/$')
+		board_dir=${board_dir%/}
+		if ! nand_upgrade_tar_dir_has_assets "$tar_file" "$board_dir" ; then
+			nand_do_upgrade_abort "No assets found for '${board_dir}/'."
+		fi
+	fi
 
-	local kernel_length=`(tar xf $tar_file ${board_dir}/kernel -O | wc -c) 2> /dev/null`
-	local rootfs_length=`(tar xf $tar_file ${board_dir}/root -O | wc -c) 2> /dev/null`
+	>&2 echo "Assets from '${board_dir}/'."
 
-	local rootfs_type="$(identify_tar "$tar_file" ${board_dir}/root)"
+	local kernel_length=$( (tar xf "$tar_file" "${board_dir}/kernel" -O | wc -c) 2> /dev/null )
+	local rootfs_length=$( (tar xf "$tar_file" "${board_dir}/root" -O | wc -c) 2> /dev/null )
 
-	local has_kernel=1
-	local has_env=0
+	local rootfs_type="$(identify_tar "$tar_file" "${board_dir}/root")"
 
-	[ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && {
+	local has_ubi_kernel=1
+	local has_ubi_env=0
+
+	[ "$kernel_length" = 0 ] || [ -n "$kernel_mtd" ] && has_ubi_kernel=0
+
+	nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_ubi_kernel" "$has_ubi_env"
+	err=$?
+	[ "$err" != 0 ] && nand_do_upgrade_abort "nand_upgrade_prepare_ubi returned '$err'"
+
+	if [ "$kernel_length" != 0 ] && [ -n "$kernel_mtd" ] ; then
 		tar xf $tar_file ${board_dir}/kernel -O | mtd write - $CI_KERNPART
-	}
-	[ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0
+	fi
 
-	nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env"
+	local ubidev="$(nand_find_ubi $CI_UBIPART)"
 
-	local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
-	[ "$has_kernel" = "1" ] && {
+	if [ "$has_ubi_kernel" = "1" ] ; then
 		local kern_ubivol="$(nand_find_volume $ubidev $CI_KERNPART)"
 		tar xf $tar_file ${board_dir}/kernel -O | \
 			ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
-	}
+	fi
 
 	local root_ubivol="$(nand_find_volume $ubidev $CI_ROOTPART)"
+
 	tar xf $tar_file ${board_dir}/root -O | \
 		ubiupdatevol /dev/$root_ubivol -s $rootfs_length -
 
@@ -279,18 +327,45 @@ nand_upgrade_tar() {
 }
 
 # Recognize type of passed file and start the upgrade process
+
 nand_do_upgrade() {
 	local file_type=$(identify $1)
 
 	[ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs"
 
 	case "$file_type" in
-		"ubi")		nand_upgrade_ubinized $1;;
-		"ubifs")	nand_upgrade_ubifs $1;;
-		*)		nand_upgrade_tar $1;;
+		"ubi")		nand_upgrade_ubinized "$1";;
+		"ubifs")	nand_upgrade_ubifs "$1";;
+		*)		nand_upgrade_tar "$1";;
 	esac
 }
 
+nand_do_upgrade_success() {
+	local conf_tar="/tmp/sysupgrade.tgz"
+
+	sync
+	[ -f "$conf_tar" ] && nand_restore_config "$conf_tar"
+	echo "sysupgrade completed"
+	umount -a
+	reboot -f
+}
+
+nand_do_upgrade_abort() {
+	>&2 echo "##### UPGRADE ABORTED: $1 #####"
+	>&2 echo "Rebooting in 5 seconds"
+	sleep 5
+	sync
+	umount -a
+	reboot -f
+}
+
+
+
+
+###
+### Use of image metadata and checks is highly encouraged over this "legacy" routine
+###
+
 # Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
 # 3 types of files:
 # 1) UBI - should contain an ubinized image, header is checked for the proper
-- 
2.20.1


_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list