mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 15:32:33 +00:00
397de50089
For sysupgrade on NAND/UBI devices there is the U-Boot environment variable rootfs_data_max which can be used to limit the size of the rootfs_data volume created on sysupgrade. This stopped working reliable with recent kernels, probably due to a race condition when reading the number of free erase blocks from sysfs just after removing a volume. Change the script to just try creating rootfs_data with the desired size and retry with maximum size in case that fails. Hence calculating the available size in the script can be dropped which works around the problem. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
355 lines
8.8 KiB
Bash
355 lines
8.8 KiB
Bash
# 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
|
|
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() {
|
|
dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
identify_magic() {
|
|
local magic=$1
|
|
case "$magic" in
|
|
"55424923")
|
|
echo "ubi"
|
|
;;
|
|
"31181006")
|
|
echo "ubifs"
|
|
;;
|
|
"68737173")
|
|
echo "squashfs"
|
|
;;
|
|
"d00dfeed")
|
|
echo "fit"
|
|
;;
|
|
"4349"*)
|
|
echo "combined"
|
|
;;
|
|
*)
|
|
echo "unknown $magic"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
|
|
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 $CI_ROOTPART )"
|
|
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/$BACKUP_FILE"
|
|
umount /tmp/new_root
|
|
sync
|
|
rmdir /tmp/new_root
|
|
}
|
|
|
|
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}"
|
|
|
|
[ -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"
|
|
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" )"
|
|
[ "$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 $CI_KERNPART )"
|
|
local root_ubivol="$( nand_find_volume $ubidev $CI_ROOTPART )"
|
|
local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
|
|
|
|
local ubiblk ubiblkvol
|
|
for ubiblk in /dev/ubiblock*_? ; do
|
|
[ -e "$ubiblk" ] || continue
|
|
echo "removing ubiblock${ubiblk:13}"
|
|
ubiblkvol=ubi${ubiblk:13}
|
|
if ! ubiblock -r /dev/$ubiblkvol; then
|
|
echo "cannot remove $ubiblk"
|
|
return 1
|
|
fi
|
|
done
|
|
|
|
# kill volumes
|
|
[ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N $CI_KERNPART || true
|
|
[ "$root_ubivol" -a "$root_ubivol" != "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N $CI_ROOTPART || true
|
|
[ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true
|
|
|
|
# update kernel
|
|
if [ -n "$kernel_length" ]; then
|
|
if ! ubimkvol /dev/$ubidev -N $CI_KERNPART -s $kernel_length; then
|
|
echo "cannot create kernel volume"
|
|
return 1;
|
|
fi
|
|
fi
|
|
|
|
# update rootfs
|
|
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/$ubidev -N $CI_ROOTPART $rootfs_size_param; then
|
|
echo "cannot create rootfs volume"
|
|
return 1;
|
|
fi
|
|
fi
|
|
|
|
# create rootfs_data 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/$ubidev -N rootfs_data $rootfs_data_size_param; then
|
|
if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
|
|
echo "cannot initialize rootfs_data volume"
|
|
return 1
|
|
fi
|
|
fi
|
|
fi
|
|
sync
|
|
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"
|
|
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 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" "" ""
|
|
|
|
local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
|
|
local root_ubivol="$(nand_find_volume $ubidev $CI_ROOTPART)"
|
|
ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1
|
|
|
|
nand_do_upgrade_success
|
|
}
|
|
|
|
nand_upgrade_fit() {
|
|
local fit_file="$1"
|
|
local fit_length="$(wc -c < "$fit_file")"
|
|
|
|
nand_upgrade_prepare_ubi "" "" "$fit_length" "1"
|
|
|
|
local fit_ubidev="$(nand_find_ubi "$CI_UBIPART")"
|
|
local fit_ubivol="$(nand_find_volume $fit_ubidev "$CI_KERNPART")"
|
|
ubiupdatevol /dev/$fit_ubivol -s $fit_length $fit_file
|
|
|
|
nand_do_upgrade_success
|
|
}
|
|
|
|
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%/}
|
|
|
|
kernel_length=$( (tar xf "$tar_file" ${board_dir}/kernel -O | wc -c) 2> /dev/null)
|
|
local has_rootfs=0
|
|
local rootfs_length
|
|
local rootfs_type
|
|
|
|
tar tf "$tar_file" ${board_dir}/root 1>/dev/null 2>/dev/null && has_rootfs=1
|
|
[ "$has_rootfs" = "1" ] && {
|
|
rootfs_length=$( (tar xf "$tar_file" ${board_dir}/root -O | wc -c) 2> /dev/null)
|
|
rootfs_type="$(identify_tar "$tar_file" ${board_dir}/root)"
|
|
}
|
|
|
|
local has_kernel=1
|
|
local has_env=0
|
|
|
|
[ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && {
|
|
tar xf "$tar_file" ${board_dir}/kernel -O | mtd write - $CI_KERNPART
|
|
}
|
|
[ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=
|
|
[ "$CI_KERNPART" = "none" ] && has_kernel=
|
|
|
|
nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "${has_kernel:+$kernel_length}" "$has_env"
|
|
|
|
local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
|
|
[ "$has_kernel" = "1" ] && {
|
|
local kern_ubivol="$( nand_find_volume $ubidev $CI_KERNPART )"
|
|
tar xf "$tar_file" ${board_dir}/kernel -O | \
|
|
ubiupdatevol /dev/$kern_ubivol -s $kernel_length -
|
|
}
|
|
|
|
[ "$has_rootfs" = "1" ] && {
|
|
local root_ubivol="$( nand_find_volume $ubidev $CI_ROOTPART )"
|
|
tar xf "$tar_file" ${board_dir}/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() {
|
|
local file_type=$(identify $1)
|
|
|
|
[ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs"
|
|
|
|
case "$file_type" in
|
|
"fit") nand_upgrade_fit $1;;
|
|
"ubi") nand_upgrade_ubinized $1;;
|
|
"ubifs") nand_upgrade_ubifs $1;;
|
|
*) nand_upgrade_tar $1;;
|
|
esac
|
|
}
|
|
|
|
# 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" -a "$file_type" != "fit" ] && {
|
|
echo "Invalid sysupgrade file."
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|