[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