procd: update to latest git HEAD
[openwrt/openwrt.git] / package / system / procd / files / nand.sh
index 7d1a55db0c4cba97e1bbe7b132fbe2f9834b44e9..9c831df3b4247d12d7e882da349eafea5894fabc 100644 (file)
@@ -4,10 +4,23 @@
 
 . /lib/functions.sh
 
-# combined-image uses 64k blocks
-CI_BLKSZ=65536
-# 'data' partition on NAND contains UBI
-CI_UBIPART="ubi"
+# 'kernel' partition on NAND contains the kernel
+CI_KERNPART="${CI_KERNPART:-kernel}"
+
+# 'ubi' partition on NAND contains UBI
+CI_UBIPART="${CI_UBIPART:-ubi}"
+
+ubi_mknod() {
+       local dir="$1"
+       local dev="/dev/$(basename $dir)"
+
+       [ -e "$dev" ] && return 0
+
+       local devid="$(cat $dir/dev)"
+       local major="${devid%%:*}"
+       local minor="${devid##*:}"
+       mknod "$dev" c $major $minor
+}
 
 nand_find_volume() {
        local ubidevdir ubivoldir
@@ -17,6 +30,7 @@ nand_find_volume() {
                [ ! -d "$ubivoldir" ] && continue
                if [ "$( cat $ubivoldir/name )" = "$2" ]; then
                        basename $ubivoldir
+                       ubi_mknod "$ubivoldir"
                        return 0
                fi
        done
@@ -32,59 +46,23 @@ nand_find_ubi() {
                [ ! "$mtdnum" ] && continue
                if [ "$mtdnum" = "$cmtdnum" ]; then
                        ubidev=$( basename $ubidevdir )
+                       ubi_mknod "$ubidevdir"
                        echo $ubidev
                        return 0
                fi
        done
 }
 
-nand_restore_config() {
-       sync
-       local ubidev=$( nand_find_ubi $CI_UBIPART )
-       local ubivol="$( nand_find_volume $ubidev rootfs_data )"
-       [ ! "$ubivol" ] &&
-               ubivol="$( nand_find_volume $ubidev rootfs )"
-       mkdir /tmp/new_root
-       if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
-               echo "mounting ubifs $ubivol failed"
-               rmdir /tmp/new_root
-               return 1
-       fi
-       mv "$1" "/tmp/new_root/sysupgrade.tgz"
-       umount /tmp/new_root
-       sync
-       rmdir /tmp/new_root
+nand_get_magic_long() {
+       dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
 }
 
-nand_upgrade_ubinized() {
-       local upgrade_image="$1"
-       local conf_tar="$2"
-       local save_config="$3"
-       local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
-       if [ ! "$mtdnum" ]; then
-               echo "cannot find mtd device $CI_UBIPART"
-               return 1;
-       fi
-       local mtddev="/dev/mtd${mtdnum}"
-       ubidetach -p "${mtddev}" || true
-       sync
-       ubiformat "${mtddev}" -y -f "$upgrade_image"
-       ubiattach -p "${mtddev}"
-       sync
-       if [ -f "$conf_tar" -a "$save_config" -eq 1 ]; then
-               nand_restore_config "$conf_tar"
-       fi
-       return 0;
+get_magic_long_tar() {
+       ( tar xf $1 $2 -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
 }
 
-# get the first 4 bytes (magic) of a given file starting at offset in hex format
-get_magic_long_at() {
-       dd if="$2" skip=$1 bs=$CI_BLKSZ count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
-}
-
-identify() {
-       local block;
-       local magic=$( get_magic_long_at ${2:-0} "$1" )
+identify_magic() {
+       local magic=$1
        case "$magic" in
                "55424923")
                        echo "ubi"
@@ -107,46 +85,63 @@ identify() {
        esac
 }
 
-nand_upgrade_combined_ubi() {
-       local kernel_image="$1"
-       local kernel_length=0
-       local rootfs_image="$2"
-       local rootfs_length=`ls -la $rootfs_image  | awk '{ print $5}')`
-       local conf_tar="$3"
+
+identify() {
+       identify_magic $(nand_get_magic_long "$1" "${2:-0}")
+}
+
+identify_tar() {
+       identify_magic $(get_magic_long_tar "$1" "$2")
+}
+
+nand_restore_config() {
+       sync
+       local ubidev=$( nand_find_ubi $CI_UBIPART )
+       local ubivol="$( nand_find_volume $ubidev rootfs_data )"
+       [ ! "$ubivol" ] &&
+               ubivol="$( nand_find_volume $ubidev rootfs )"
+       mkdir /tmp/new_root
+       if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
+               echo "mounting ubifs $ubivol failed"
+               rmdir /tmp/new_root
+               return 1
+       fi
+       mv "$1" "/tmp/new_root/sysupgrade.tgz"
+       umount /tmp/new_root
+       sync
+       rmdir /tmp/new_root
+}
+
+nand_upgrade_prepare_ubi() {
+       local rootfs_length="$1"
+       local rootfs_type="$2"
+       local has_kernel="${3:-0}"
        local has_env="${4:-0}"
 
-       local root_fs="$( identify "$rootfs_image" )"
        local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
-       local has_kernel=0
-       
-       [ -z "$kernel_image" ] || {
-               has_kernel=1 
-               kernel_length=`ls -la $kernel_image  | awk '{ print $5}')`
-               echo "kernel length $kernel_length"
-       }
-       [ "$has_kernel" = 0 ] || echo "kernel is inside ubi"
-       echo "rootfs type $root_fs, length $rootfs_length"
-
        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"
                sync
                ubidev="$( nand_find_ubi "$CI_UBIPART" )"
        fi
+
        if [ ! "$ubidev" ]; then
                ubiformat /dev/mtd$mtdnum -y
                ubiattach -m "$mtdnum"
                sync
                ubidev="$( nand_find_ubi "$CI_UBIPART" )"
-               [ -z "$has_env" ] || {
+               [ "$has_env" -gt 0 ] && {
                        ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
                        ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
                }
        fi
+
        local kern_ubivol="$( nand_find_volume $ubidev kernel )"
        local root_ubivol="$( nand_find_volume $ubidev rootfs )"
        local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
@@ -162,15 +157,9 @@ nand_upgrade_combined_ubi() {
        fi
 
        # kill volumes
-       if [ "$kern_ubivol" ]; then
-               ubirmvol /dev/$ubidev -N kernel || true
-       fi
-       if [ "$root_ubivol" ]; then
-               ubirmvol /dev/$ubidev -N rootfs || true
-       fi
-       if [ "$data_ubivol" ]; then
-               ubirmvol /dev/$ubidev -N rootfs_data || true
-       fi
+       [ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N kernel || true
+       [ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs || true
+       [ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true
 
        # update kernel
        if [ "$has_kernel" = "1" ]; then
@@ -182,7 +171,7 @@ nand_upgrade_combined_ubi() {
 
        # update rootfs
        local root_size_param
-       if [ "$root_fs" = "ubifs" ]; then
+       if [ "$rootfs_type" = "ubifs" ]; then
                root_size_param="-m"
        else
                root_size_param="-s $rootfs_length"
@@ -193,78 +182,126 @@ nand_upgrade_combined_ubi() {
        fi
 
        # create rootfs_data for non-ubifs rootfs
-       if [ "$root_fs" != "ubifs" ]; then
+       if [ "$rootfs_type" != "ubifs" ]; then
                if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
                        echo "cannot initialize rootfs_data volume"
                        return 1
                fi
        fi
        sync
+       return 0
+}
 
-       if [ "$has_kernel" = "1" ]; then
-               local kern_ubivol="$( nand_find_volume $ubidev kernel )"
-               ubiupdatevol /dev/$kern_ubivol -s $kernel_length $kernel_image
+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"
+       local mtdnum="$(find_mtd_index "$CI_UBIPART")"
+
+       [ ! "$mtdnum" ] && {
+               CI_UBIPART="rootfs"
+               mtdnum="$(find_mtd_index "$CI_UBIPART")"
+       }
+
+       if [ ! "$mtdnum" ]; then
+               echo "cannot find mtd device $CI_UBIPART"
+               umount -a
+               reboot -f
        fi
 
-       local root_ubivol="$( nand_find_volume $ubidev rootfs )"
-       ubiupdatevol /dev/$root_ubivol -s $rootfs_length $rootfs_image
-       if [ -f "$conf_tar" ]; then
-               nand_restore_config "$conf_tar"
+       local mtddev="/dev/mtd${mtdnum}"
+       ubidetach -p "${mtddev}" || true
+       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`
+
+       nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0"
+
+       local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+       local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+       ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
+
+       nand_do_upgrade_success
+}
+
+nand_board_name() {
+       if type 'platform_nand_board_name' >/dev/null 2>/dev/null; then
+               platform_nand_board_name
+               return
        fi
-       echo "sysupgrade successfull"
-       return 0
+
+       cat /tmp/sysinfo/board_name
 }
 
-nand_do_upgrade_stage1() {
-       local board_name="$1"
-       local tar_file="$2"
-       local kernel_file=""
-       local kernel_file=""
+nand_upgrade_tar() {
+       local tar_file="$1"
+       local board_name="$(nand_board_name)"
+       local kernel_mtd="$(find_mtd_index $CI_KERNPART)"
 
-       tar xzf $tar_file -C /tmp/
-       [ -f "/tmp/sysupgrade-$board_name/CONTROL" ] || {
-               echo "failed to find /tmp/sysupgrade-$board_name/CONTROL"
-               return 1
-       }
+       local kernel_length=`(tar xf $tar_file sysupgrade-$board_name/kernel -O | wc -c) 2> /dev/null`
+       local rootfs_length=`(tar xf $tar_file sysupgrade-$board_name/root -O | wc -c) 2> /dev/null`
 
-       kernel_file=/tmp/sysupgrade-$board_name/kernel
-       [ -f "$kernel_file" ] || {
-               echo "$kernel_file is missing"
-               return 1
+       local rootfs_type="$(identify_tar "$tar_file" sysupgrade-$board_name/root)"
+
+       local has_kernel=1
+       local has_env=0
+
+       [ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && {
+               tar xf $tar_file sysupgrade-$board_name/kernel -O | mtd write - $CI_KERNPART
        }
+       [ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0
 
-       rootfs_file=/tmp/sysupgrade-$board_name/root
-       [ -f "$rootfs_file" ] || {
-               echo "$rootfs_file is missing"
-               return 1
+       nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env"
+
+       local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
+       [ "$has_kernel" = "1" ] && {
+               local kern_ubivol="$(nand_find_volume $ubidev kernel)"
+               tar xf $tar_file sysupgrade-$board_name/kernel -O | \
+                       ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
        }
-       
-       echo -n /tmp/sysupgrade-$board_name > /tmp/sysupgrade-nand-folder
-       cp /sbin/upgraded /tmp/
 
-       return 0
+       local root_ubivol="$(nand_find_volume $ubidev rootfs)"
+       tar xf $tar_file sysupgrade-$board_name/root -O | \
+               ubiupdatevol /dev/$root_ubivol -s $rootfs_length -
+
+       nand_do_upgrade_success
 }
 
+# Recognize type of passed file and start the upgrade process
 nand_do_upgrade_stage2() {
-       rootfs_file=$1/root
-       kernel_file=$1/kernel
-       config_file=$1/config
+       local file_type=$(identify $1)
 
-       [ -f $config_file ] || config_file=""
+       if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
+               platform_nand_pre_upgrade "$1"
+       fi
 
-       . $1/CONTROL
+       [ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs"
 
-       [ "$UBI_KERNEL" = "1" ] || {
-               mtd write $kernel_file kernel
-               kernel_file=""
-       }
-       nand_upgrade_combined_ubi "$kernel_file" "$rootfs_file" "$conf_tar" "$UBI_ENV"
-       reboot -f
+       case "$file_type" in
+               "ubi")          nand_upgrade_ubinized $1;;
+               "ubifs")        nand_upgrade_ubifs $1;;
+               *)              nand_upgrade_tar $1;;
+       esac
 }
 
-nand_do_upgrade() {
+nand_upgrade_stage2() {
        [ $1 = "nand" ] && {
-               [ -d "$2" ] && {
+               [ -f "$2" ] && {
                        touch /tmp/sysupgrade
 
                        killall -9 telnetd
@@ -291,13 +328,49 @@ nand_do_upgrade() {
 }
 
 nand_upgrade_stage1() {
-       [ -f /tmp/sysupgrade-nand-folder ] && {
-               folder="$(cat /tmp/sysupgrade-nand-folder)"
-               [ "$SAVE_CONFIG" = 1 -a -f "$CONF_TAR" ] &&
-                       cp $CONF_TAR $folder/config
+       [ -f /tmp/sysupgrade-nand-path ] && {
+               path="$(cat /tmp/sysupgrade-nand-path)"
+               [ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
+                       rm $CONF_TAR
 
-               ubus call system nandupgrade "{\"folder\": \"$folder\" }"
+               ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
                exit 0
        }
 }
-append sysupgrade_pre_upgrade nand_upgrade_stage1
+
+# 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
+#    MAGIC
+# 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume,
+#    header is checked for the proper MAGIC
+# 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty
+#    "CONTROL" file (at this point its content isn't verified)
+#
+# You usually want to call this function in platform_check_image.
+#
+# $(1): board name, used in case of passing TAR file
+# $(2): file to be checked
+nand_do_platform_check() {
+       local board_name="$1"
+       local tar_file="$2"
+       local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null`
+       local file_type="$(identify $2)"
+
+       [ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ] && {
+               echo "Invalid sysupgrade file."
+               return 1
+       }
+
+       return 0
+}
+
+# Start NAND upgrade process
+#
+# $(1): file to be used for upgrade
+nand_do_upgrade() {
+       echo -n $1 > /tmp/sysupgrade-nand-path
+       install_bin /sbin/upgraded
+       ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
+       nand_upgrade_stage1
+}