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