base-files: sysupgrade-tar: allow separated kernel/rootfs ubi
[openwrt/staging/noltari.git] / package / base-files / files / lib / upgrade / nand.sh
index 496e5bf7fba7b7e7fc5e29c8e905bec2242d28be..a8e3cab0b8b112d052f27c08c4e25791cd8ba57b 100644 (file)
@@ -7,6 +7,8 @@
 CI_KERNPART="${CI_KERNPART:-kernel}"
 
 # 'ubi' partition on NAND contains UBI
+# There are also CI_KERN_UBIPART and CI_ROOT_UBIPART if kernel
+# and rootfs are on separated UBIs.
 CI_UBIPART="${CI_UBIPART:-ubi}"
 
 # 'rootfs' UBI volume on NAND contains the rootfs
@@ -60,7 +62,7 @@ nand_get_magic_long() {
 }
 
 get_magic_long_tar() {
-       (tar x${3}f "$1" "$2" -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
+       (tar xO${3}f "$1" "$2" | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
 }
 
 identify_magic() {
@@ -104,7 +106,7 @@ identify_if_gzip() {
 }
 
 nand_restore_config() {
-       local ubidev=$( nand_find_ubi "$CI_UBIPART" )
+       local ubidev=$( nand_find_ubi "${CI_ROOT_UBIPART:-$CI_UBIPART}" )
        local ubivol="$( nand_find_volume $ubidev rootfs_data )"
        if [ ! "$ubivol" ]; then
                ubivol="$( nand_find_volume $ubidev "$CI_ROOTPART" )"
@@ -146,6 +148,42 @@ nand_remove_ubiblock() {
        fi
 }
 
+nand_attach_ubi() {
+       local ubipart="$1"
+       local has_env="${2:-0}"
+
+       local mtdnum="$( find_mtd_index "$ubipart" )"
+       if [ ! "$mtdnum" ]; then
+               >&2 echo "cannot find ubi mtd partition $ubipart"
+               return 1
+       fi
+
+       local ubidev="$( nand_find_ubi "$ubipart" )"
+       if [ ! "$ubidev" ]; then
+               >&2 ubiattach -m "$mtdnum"
+               ubidev="$( nand_find_ubi "$ubipart" )"
+
+               if [ ! "$ubidev" ]; then
+                       >&2 ubiformat /dev/mtd$mtdnum -y
+                       >&2 ubiattach -m "$mtdnum"
+                       ubidev="$( nand_find_ubi "$ubipart" )"
+
+                       if [ ! "$ubidev" ]; then
+                               >&2 echo "cannot attach ubi mtd partition $ubipart"
+                               return 1
+                       fi
+
+                       if [ "$has_env" -gt 0 ]; then
+                               >&2 ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
+                               >&2 ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
+                       fi
+               fi
+       fi
+
+       echo "$ubidev"
+       return 0
+}
+
 nand_detach_ubi() {
        local ubipart="$1"
 
@@ -172,45 +210,30 @@ nand_detach_ubi() {
 nand_upgrade_prepare_ubi() {
        local rootfs_length="$1"
        local rootfs_type="$2"
-       local rootfs_data_max="$(fw_printenv -n rootfs_data_max 2>/dev/null)"
+       local rootfs_data_max="$(fw_printenv -n rootfs_data_max 2> /dev/null)"
        [ -n "$rootfs_data_max" ] && rootfs_data_max=$((rootfs_data_max))
 
        local kernel_length="$3"
        local has_env="${4:-0}"
+       local kern_ubidev
+       local root_ubidev
 
        [ -n "$rootfs_length" -o -n "$kernel_length" ] || return 1
 
-       local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
-       if [ ! "$mtdnum" ]; then
-               echo "cannot find ubi mtd partition $CI_UBIPART"
-               return 1
-       fi
-
-       local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
-       if [ ! "$ubidev" ]; then
-               ubiattach -m "$mtdnum"
-               ubidev="$( nand_find_ubi "$CI_UBIPART" )"
-
-               if [ ! "$ubidev" ]; then
-                       ubiformat /dev/mtd$mtdnum -y
-                       ubiattach -m "$mtdnum"
-                       ubidev="$( nand_find_ubi "$CI_UBIPART" )"
-
-                       if [ ! "$ubidev" ]; then
-                               echo "cannot attach ubi mtd partition $CI_UBIPART"
-                               return 1
-                       fi
-
-                       if [ "$has_env" -gt 0 ]; then
-                               ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
-                               ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
-                       fi
-               fi
+       if [ -n "$CI_KERN_UBIPART" -a -n "$CI_ROOT_UBIPART" ]; then
+               kern_ubidev="$( nand_attach_ubi "$CI_KERN_UBIPART" "$has_env" )"
+               [ -n "$kern_ubidev" ] || return 1
+               root_ubidev="$( nand_attach_ubi "$CI_ROOT_UBIPART" )"
+               [ -n "$root_ubidev" ] || return 1
+       else
+               kern_ubidev="$( nand_attach_ubi "$CI_UBIPART" "$has_env" )"
+               [ -n "$kern_ubidev" ] || return 1
+               root_ubidev="$kern_ubidev"
        fi
 
-       local kern_ubivol="$( nand_find_volume $ubidev "$CI_KERNPART" )"
-       local root_ubivol="$( nand_find_volume $ubidev "$CI_ROOTPART" )"
-       local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
+       local kern_ubivol="$( nand_find_volume $kern_ubidev "$CI_KERNPART" )"
+       local root_ubivol="$( nand_find_volume $root_ubidev "$CI_ROOTPART" )"
+       local data_ubivol="$( nand_find_volume $root_ubidev rootfs_data )"
        [ "$root_ubivol" = "$kern_ubivol" ] && root_ubivol=
 
        # remove ubiblocks
@@ -219,13 +242,13 @@ nand_upgrade_prepare_ubi() {
        [ "$data_ubivol" ] && { nand_remove_ubiblock $data_ubivol || return 1; }
 
        # kill volumes
-       [ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N "$CI_KERNPART" || :
-       [ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N "$CI_ROOTPART" || :
-       [ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || :
+       [ "$kern_ubivol" ] && ubirmvol /dev/$kern_ubidev -N "$CI_KERNPART" || :
+       [ "$root_ubivol" ] && ubirmvol /dev/$root_ubidev -N "$CI_ROOTPART" || :
+       [ "$data_ubivol" ] && ubirmvol /dev/$root_ubidev -N rootfs_data || :
 
        # create kernel vol
        if [ -n "$kernel_length" ]; then
-               if ! ubimkvol /dev/$ubidev -N "$CI_KERNPART" -s $kernel_length; then
+               if ! ubimkvol /dev/$kern_ubidev -N "$CI_KERNPART" -s $kernel_length; then
                        echo "cannot create kernel volume"
                        return 1;
                fi
@@ -239,7 +262,7 @@ nand_upgrade_prepare_ubi() {
                else
                        rootfs_size_param="-s $rootfs_length"
                fi
-               if ! ubimkvol /dev/$ubidev -N "$CI_ROOTPART" $rootfs_size_param; then
+               if ! ubimkvol /dev/$root_ubidev -N "$CI_ROOTPART" $rootfs_size_param; then
                        echo "cannot create rootfs volume"
                        return 1;
                fi
@@ -251,8 +274,8 @@ nand_upgrade_prepare_ubi() {
                if [ -n "$rootfs_data_max" ]; then
                        rootfs_data_size_param="-s $rootfs_data_max"
                fi
-               if ! ubimkvol /dev/$ubidev -N rootfs_data $rootfs_data_size_param; then
-                       if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
+               if ! ubimkvol /dev/$root_ubidev -N rootfs_data $rootfs_data_size_param; then
+                       if ! ubimkvol /dev/$root_ubidev -N rootfs_data -m; then
                                echo "cannot initialize rootfs_data volume"
                                return 1
                        fi
@@ -313,10 +336,10 @@ nand_upgrade_tar() {
        local kernel_mtd kernel_length
        if [ "$CI_KERNPART" != "none" ]; then
                kernel_mtd="$(find_mtd_index "$CI_KERNPART")"
-               kernel_length=$( (tar x${gz}f "$tar_file" "$board_dir/kernel" -O | wc -c) 2> /dev/null)
+               kernel_length=$( (tar xO${gz}f "$tar_file" "$board_dir/kernel" | wc -c) 2> /dev/null)
                [ "$kernel_length" = 0 ] && kernel_length=
        fi
-       local rootfs_length=$( (tar x${gz}f "$tar_file" "$board_dir/root" -O | wc -c) 2> /dev/null)
+       local rootfs_length=$( (tar xO${gz}f "$tar_file" "$board_dir/root" | wc -c) 2> /dev/null)
        [ "$rootfs_length" = 0 ] && rootfs_length=
        local rootfs_type
        [ "$rootfs_length" ] && rootfs_type="$(identify_tar "$tar_file" "$board_dir/root" "$gz")"
@@ -327,7 +350,7 @@ nand_upgrade_tar() {
                        # On some devices, the raw kernel and ubi partitions overlap.
                        # These devices brick if the kernel partition is erased.
                        # Hence only invalidate kernel for now.
-                       dd if=/dev/zero bs=4096 count=1 2>/dev/null | \
+                       dd if=/dev/zero bs=4096 count=1 2> /dev/null | \
                                mtd write - "$CI_KERNPART"
                else
                        ubi_kernel_length="$kernel_length"
@@ -336,19 +359,20 @@ nand_upgrade_tar() {
        local has_env=0
        nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$ubi_kernel_length" "$has_env" || return 1
 
-       local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
        if [ "$rootfs_length" ]; then
+               local ubidev="$( nand_find_ubi "${CI_ROOT_UBIPART:-$CI_UBIPART}" )"
                local root_ubivol="$( nand_find_volume $ubidev "$CI_ROOTPART" )"
-               tar x${gz}f "$tar_file" "$board_dir/root" -O | \
+               tar xO${gz}f "$tar_file" "$board_dir/root" | \
                        ubiupdatevol /dev/$root_ubivol -s "$rootfs_length" -
        fi
        if [ "$kernel_length" ]; then
                if [ "$kernel_mtd" ]; then
-                       tar x${gz}f "$tar_file" "$board_dir/kernel" -O | \
+                       tar xO${gz}f "$tar_file" "$board_dir/kernel" | \
                                mtd write - "$CI_KERNPART"
                else
+                       local ubidev="$( nand_find_ubi "${CI_KERN_UBIPART:-$CI_UBIPART}" )"
                        local kern_ubivol="$( nand_find_volume $ubidev "$CI_KERNPART" )"
-                       tar x${gz}f "$tar_file" "$board_dir/kernel" -O | \
+                       tar xO${gz}f "$tar_file" "$board_dir/kernel" | \
                                ubiupdatevol /dev/$kern_ubivol -s "$kernel_length" -
                fi
        fi
@@ -356,21 +380,55 @@ nand_upgrade_tar() {
        return 0
 }
 
+nand_verify_if_gzip_file() {
+       local file="$1"
+       local gz="$2"
+
+       if [ "$gz" = z ]; then
+               echo "verifying compressed sysupgrade file integrity"
+               if ! gzip -t "$file"; then
+                       echo "corrupted compressed sysupgrade file"
+                       return 1
+               fi
+       fi
+}
+
+nand_verify_tar_file() {
+       local file="$1"
+       local gz="$2"
+
+       echo "verifying sysupgrade tar file integrity"
+       if ! tar xO${gz}f "$file" > /dev/null; then
+               echo "corrupted sysupgrade tar file"
+               return 1
+       fi
+}
+
 nand_do_flash_file() {
        local file="$1"
 
        local gz="$(identify_if_gzip "$file")"
        local file_type="$(identify "$file" "" "$gz")"
 
-       [ "$gz" = z ] && echo "detected compressed firmware file"
-
        [ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART=rootfs
 
        case "$file_type" in
-               "fit")          nand_upgrade_fit "$file" "$gz";;
-               "ubi")          nand_upgrade_ubinized "$file" "$gz";;
-               "ubifs")        nand_upgrade_ubifs "$file" "$gz";;
-               *)              nand_upgrade_tar "$file" "$gz";;
+               "fit")
+                       nand_verify_if_gzip_file "$file" "$gz" || return 1
+                       nand_upgrade_fit "$file" "$gz"
+                       ;;
+               "ubi")
+                       nand_verify_if_gzip_file "$file" "$gz" || return 1
+                       nand_upgrade_ubinized "$file" "$gz"
+                       ;;
+               "ubifs")
+                       nand_verify_if_gzip_file "$file" "$gz" || return 1
+                       nand_upgrade_ubifs "$file" "$gz"
+                       ;;
+               *)
+                       nand_verify_tar_file "$file" "$gz" || return 1
+                       nand_upgrade_tar "$file" "$gz"
+                       ;;
        esac
 }
 
@@ -384,12 +442,20 @@ nand_do_upgrade() {
        local file="$1"
 
        sync
-       if nand_do_flash_file "$file" && nand_do_restore_config && sync; then
+       nand_do_flash_file "$file" && nand_do_upgrade_success
+       nand_do_upgrade_failed
+}
+
+nand_do_upgrade_success() {
+       if nand_do_restore_config && sync; then
                echo "sysupgrade successful"
                umount -a
                reboot -f
        fi
+       nand_do_upgrade_failed
+}
 
+nand_do_upgrade_failed() {
        sync
        echo "sysupgrade failed"
        # Should we reboot or bring up some failsafe mode instead?
@@ -415,12 +481,16 @@ nand_do_platform_check() {
 
        local gz="$(identify_if_gzip "$file")"
        local file_type="$(identify "$file" "" "$gz")"
+       local control_length=$( (tar xO${gz}f "$file" "sysupgrade-$board_name/CONTROL" | wc -c) 2> /dev/null)
 
-       local control_length=$( (tar x${gz}f "$file" "sysupgrade-$board_name/CONTROL" -O | wc -c) 2> /dev/null)
-
-       if [ "$file_type" != "fit" -a "$file_type" != "ubi" -a "$file_type" != "ubifs" -a "$control_length" = 0 ]; then
-               echo "invalid sysupgrade file"
-               return 1
+       if [ "$control_length" != 0 ]; then
+               nand_verify_tar_file "$file" "$gz" || return 1
+       else
+               nand_verify_if_gzip_file "$file" "$gz" || return 1
+               if [ "$file_type" != "fit" -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ]; then
+                       echo "invalid sysupgrade file"
+                       return 1
+               fi
        fi
 
        return 0