123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- # Copyright (C) 2014 OpenWrt.org
- #
- . /lib/functions.sh
- # 'kernel' partition or UBI volume on NAND contains the kernel
- 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
- CI_ROOTPART="${CI_ROOTPART:-rootfs}"
- 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
- ubidevdir="/sys/devices/virtual/ubi/$1"
- [ ! -d "$ubidevdir" ] && return 1
- for ubivoldir in $ubidevdir/${1}_*; do
- [ ! -d "$ubivoldir" ] && continue
- if [ "$( cat $ubivoldir/name )" = "$2" ]; then
- basename $ubivoldir
- ubi_mknod "$ubivoldir"
- return 0
- fi
- done
- }
- nand_find_ubi() {
- local ubidevdir ubidev mtdnum
- mtdnum="$( find_mtd_index $1 )"
- [ ! "$mtdnum" ] && return 1
- for ubidevdir in /sys/devices/virtual/ubi/ubi*; do
- [ ! -d "$ubidevdir" ] && continue
- cmtdnum="$( cat $ubidevdir/mtd_num )"
- [ ! "$mtdnum" ] && continue
- if [ "$mtdnum" = "$cmtdnum" ]; then
- ubidev=$( basename $ubidevdir )
- ubi_mknod "$ubidevdir"
- echo $ubidev
- return 0
- fi
- done
- }
- nand_get_magic_long() {
- (${3}cat "$1" | dd bs=4 "skip=${2:-0}" count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
- }
- get_magic_long_tar() {
- (tar xO${3}f "$1" "$2" | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null
- }
- identify() {
- identify_magic_long $(nand_get_magic_long "$@")
- }
- identify_tar() {
- identify_magic_long $(get_magic_long_tar "$@")
- }
- identify_if_gzip() {
- if [ "$(identify "$1")" = gzip ]; then echo -n z; fi
- }
- nand_restore_config() {
- 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" )"
- if [ ! "$ubivol" ]; then
- echo "cannot find ubifs data volume"
- return 1
- fi
- fi
- mkdir /tmp/new_root
- if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
- echo "cannot mount ubifs volume $ubivol"
- rmdir /tmp/new_root
- return 1
- fi
- if mv "$1" "/tmp/new_root/$BACKUP_FILE"; then
- if umount /tmp/new_root; then
- echo "configuration saved"
- rmdir /tmp/new_root
- return 0
- fi
- else
- umount /tmp/new_root
- fi
- echo "could not save configuration to ubifs volume $ubivol"
- rmdir /tmp/new_root
- return 1
- }
- nand_remove_ubiblock() {
- local ubivol="$1"
- local ubiblk="ubiblock${ubivol:3}"
- if [ -e "/dev/$ubiblk" ]; then
- umount "/dev/$ubiblk" && echo "unmounted /dev/$ubiblk" || :
- if ! ubiblock -r "/dev/$ubivol"; then
- echo "cannot remove $ubiblk"
- return 1
- fi
- 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"
- local mtdnum="$( find_mtd_index "$ubipart" )"
- if [ ! "$mtdnum" ]; then
- echo "cannot find ubi mtd partition $ubipart"
- return 1
- fi
- local ubidev="$( nand_find_ubi "$ubipart" )"
- if [ "$ubidev" ]; then
- for ubivol in $(find /dev -name "${ubidev}_*" -maxdepth 1 | sort); do
- ubivol="${ubivol:5}"
- nand_remove_ubiblock "$ubivol" || :
- umount "/dev/$ubivol" && echo "unmounted /dev/$ubivol" || :
- done
- if ! ubidetach -m "$mtdnum"; then
- echo "cannot detach ubi mtd partition $ubipart"
- return 1
- fi
- fi
- }
- 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)"
- [ -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
- 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 $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
- [ "$kern_ubivol" ] && { nand_remove_ubiblock $kern_ubivol || return 1; }
- [ "$root_ubivol" ] && { nand_remove_ubiblock $root_ubivol || return 1; }
- [ "$data_ubivol" ] && { nand_remove_ubiblock $data_ubivol || return 1; }
- # kill volumes
- [ "$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/$kern_ubidev -N "$CI_KERNPART" -s $kernel_length; then
- echo "cannot create kernel volume"
- return 1;
- fi
- fi
- # create rootfs vol
- if [ -n "$rootfs_length" ]; then
- local rootfs_size_param
- if [ "$rootfs_type" = "ubifs" ]; then
- rootfs_size_param="-m"
- else
- rootfs_size_param="-s $rootfs_length"
- fi
- if ! ubimkvol /dev/$root_ubidev -N "$CI_ROOTPART" $rootfs_size_param; then
- echo "cannot create rootfs volume"
- return 1;
- fi
- fi
- # create rootfs_data vol for non-ubifs rootfs
- if [ "$rootfs_type" != "ubifs" ]; then
- local rootfs_data_size_param="-m"
- if [ -n "$rootfs_data_max" ]; then
- rootfs_data_size_param="-s $rootfs_data_max"
- fi
- 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
- fi
- fi
- return 0
- }
- # Write the UBI image to MTD ubi partition
- nand_upgrade_ubinized() {
- local ubi_file="$1"
- local gz="$2"
- nand_detach_ubi "$CI_UBIPART" || return 1
- local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
- ${gz}cat "$ubi_file" | ubiformat "/dev/mtd$mtdnum" -y -f - && ubiattach -m "$mtdnum"
- }
- # Write the UBIFS image to UBI rootfs volume
- nand_upgrade_ubifs() {
- local ubifs_file="$1"
- local gz="$2"
- local ubifs_length=$( (${gz}cat "$ubifs_file" | wc -c) 2> /dev/null)
- nand_upgrade_prepare_ubi "$ubifs_length" "ubifs" "" "" || return 1
- local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
- local root_ubivol="$(nand_find_volume $ubidev "$CI_ROOTPART")"
- ${gz}cat "$ubifs_file" | ubiupdatevol /dev/$root_ubivol -s "$ubifs_length" -
- }
- # Write the FIT image to UBI kernel volume
- nand_upgrade_fit() {
- local fit_file="$1"
- local gz="$2"
- local fit_length=$( (${gz}cat "$fit_file" | wc -c) 2> /dev/null)
- nand_upgrade_prepare_ubi "" "" "$fit_length" "1" || return 1
- local fit_ubidev="$(nand_find_ubi "$CI_UBIPART")"
- local fit_ubivol="$(nand_find_volume $fit_ubidev "$CI_KERNPART")"
- ${gz}cat "$fit_file" | ubiupdatevol /dev/$fit_ubivol -s "$fit_length" -
- }
- # Write images in the TAR file to MTD partitions and/or UBI volumes as required
- nand_upgrade_tar() {
- local tar_file="$1"
- local gz="$2"
- # WARNING: This fails if tar contains more than one 'sysupgrade-*' directory.
- local board_dir="$(tar t${gz}f "$tar_file" | grep -m 1 '^sysupgrade-.*/$')"
- board_dir="${board_dir%/}"
- local kernel_mtd kernel_length
- if [ "$CI_KERNPART" != "none" ]; then
- kernel_mtd="$(find_mtd_index "$CI_KERNPART")"
- 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 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")"
- local ubi_kernel_length
- if [ "$kernel_length" ]; then
- if [ "$kernel_mtd" ]; then
- # 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 | \
- mtd write - "$CI_KERNPART"
- else
- ubi_kernel_length="$kernel_length"
- fi
- fi
- local has_env=0
- nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$ubi_kernel_length" "$has_env" || return 1
- if [ "$rootfs_length" ]; then
- local ubidev="$( nand_find_ubi "${CI_ROOT_UBIPART:-$CI_UBIPART}" )"
- local root_ubivol="$( nand_find_volume $ubidev "$CI_ROOTPART" )"
- 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 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 xO${gz}f "$tar_file" "$board_dir/kernel" | \
- ubiupdatevol /dev/$kern_ubivol -s "$kernel_length" -
- fi
- fi
- 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")"
- [ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART=rootfs
- case "$file_type" in
- "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
- }
- nand_do_restore_config() {
- local conf_tar="/tmp/sysupgrade.tgz"
- [ ! -f "$conf_tar" ] || nand_restore_config "$conf_tar"
- }
- # Recognize type of passed file and start the upgrade process
- nand_do_upgrade() {
- local file="$1"
- sync
- 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?
- umount -a
- reboot -f
- }
- # Check if passed file is a valid one for NAND sysupgrade.
- # Currently it accepts 4 types of files:
- # 1) UBI: a ubinized image containing required UBI volumes.
- # 2) UBIFS: a UBIFS rootfs volume image.
- # 3) FIT: a FIT image containing kernel and rootfs.
- # 4) TAR: an archive that includes directory "sysupgrade-${BOARD_NAME}" containing
- # a non-empty "CONTROL" file and required partition and/or volume images.
- #
- # 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 file="$2"
- 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)
- 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
- }
|