From: Jeff Kletsky <git-comm...@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-comm...@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@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to