1#!/bin/sh 2# Copyright (C) 2014 OpenWrt.org 3# 4 5. /lib/functions.sh 6 7# 'kernel' partition on NAND contains the kernel 8CI_KERNPART="kernel" 9 10# 'ubi' partition on NAND contains UBI 11CI_UBIPART="ubi" 12 13ubi_mknod() { 14 local dir="$1" 15 local dev="/dev/$(basename $dir)" 16 17 [ -e "$dev" ] && return 0 18 19 local devid="$(cat $dir/dev)" 20 local major="${devid%%:*}" 21 local minor="${devid##*:}" 22 mknod "$dev" c $major $minor 23} 24 25nand_find_volume() { 26 local ubidevdir ubivoldir 27 ubidevdir="/sys/devices/virtual/ubi/$1" 28 [ ! -d "$ubidevdir" ] && return 1 29 for ubivoldir in $ubidevdir/${1}_*; do 30 [ ! -d "$ubivoldir" ] && continue 31 if [ "$( cat $ubivoldir/name )" = "$2" ]; then 32 basename $ubivoldir 33 ubi_mknod "$ubivoldir" 34 return 0 35 fi 36 done 37} 38 39nand_find_ubi() { 40 local ubidevdir ubidev mtdnum 41 mtdnum="$( find_mtd_index $1 )" 42 [ ! "$mtdnum" ] && return 1 43 for ubidevdir in /sys/devices/virtual/ubi/ubi*; do 44 [ ! -d "$ubidevdir" ] && continue 45 cmtdnum="$( cat $ubidevdir/mtd_num )" 46 [ ! "$mtdnum" ] && continue 47 if [ "$mtdnum" = "$cmtdnum" ]; then 48 ubidev=$( basename $ubidevdir ) 49 ubi_mknod "$ubidevdir" 50 echo $ubidev 51 return 0 52 fi 53 done 54} 55 56nand_get_magic_long() { 57 dd if="$1" skip=$2 bs=4 count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"' 58} 59 60get_magic_long_tar() { 61 ( tar xf $1 $2 -O | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2> /dev/null 62} 63 64identify_magic() { 65 local magic=$1 66 case "$magic" in 67 "55424923") 68 echo "ubi" 69 ;; 70 "31181006") 71 echo "ubifs" 72 ;; 73 "68737173") 74 echo "squashfs" 75 ;; 76 "d00dfeed") 77 echo "fit" 78 ;; 79 "4349"*) 80 echo "combined" 81 ;; 82 *) 83 echo "unknown $magic" 84 ;; 85 esac 86} 87 88 89identify() { 90 identify_magic $(nand_get_magic_long "$1" "${2:-0}") 91} 92 93identify_tar() { 94 identify_magic $(get_magic_long_tar "$1" "$2") 95} 96 97nand_restore_config() { 98 sync 99 local ubidev=$( nand_find_ubi $CI_UBIPART ) 100 local ubivol="$( nand_find_volume $ubidev rootfs_data )" 101 [ ! "$ubivol" ] && 102 ubivol="$( nand_find_volume $ubidev rootfs )" 103 mkdir /tmp/new_root 104 if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then 105 echo "mounting ubifs $ubivol failed" 106 rmdir /tmp/new_root 107 return 1 108 fi 109 mv "$1" "/tmp/new_root/sysupgrade.tgz" 110 umount /tmp/new_root 111 sync 112 rmdir /tmp/new_root 113} 114 115nand_upgrade_prepare_ubi() { 116 local rootfs_length="$1" 117 local rootfs_type="$2" 118 local has_kernel="${3:-0}" 119 local has_env="${4:-0}" 120 121 local mtdnum="$( find_mtd_index "$CI_UBIPART" )" 122 if [ ! "$mtdnum" ]; then 123 echo "cannot find ubi mtd partition $CI_UBIPART" 124 return 1 125 fi 126 127 local ubidev="$( nand_find_ubi "$CI_UBIPART" )" 128 if [ ! "$ubidev" ]; then 129 ubiattach -m "$mtdnum" 130 sync 131 ubidev="$( nand_find_ubi "$CI_UBIPART" )" 132 fi 133 134 if [ ! "$ubidev" ]; then 135 ubiformat /dev/mtd$mtdnum -y 136 ubiattach -m "$mtdnum" 137 sync 138 ubidev="$( nand_find_ubi "$CI_UBIPART" )" 139 [ "$has_env" -gt 0 ] && { 140 ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB 141 ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB 142 } 143 fi 144 145 local kern_ubivol="$( nand_find_volume $ubidev kernel )" 146 local root_ubivol="$( nand_find_volume $ubidev rootfs )" 147 local data_ubivol="$( nand_find_volume $ubidev rootfs_data )" 148 149 # remove ubiblock device of rootfs 150 local root_ubiblk="ubiblock${root_ubivol:3}" 151 if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then 152 echo "removing $root_ubiblk" 153 if ! ubiblock -r /dev/$root_ubivol; then 154 echo "cannot remove $root_ubiblk" 155 return 1; 156 fi 157 fi 158 159 # kill volumes 160 [ "$kern_ubivol" ] && ubirmvol /dev/$ubidev -N kernel || true 161 [ "$root_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs || true 162 [ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N rootfs_data || true 163 164 # update kernel 165 if [ "$has_kernel" = "1" ]; then 166 if ! ubimkvol /dev/$ubidev -N kernel -s $kernel_length; then 167 echo "cannot create kernel volume" 168 return 1; 169 fi 170 fi 171 172 # update rootfs 173 local root_size_param 174 if [ "$rootfs_type" = "ubifs" ]; then 175 root_size_param="-m" 176 else 177 root_size_param="-s $rootfs_length" 178 fi 179 if ! ubimkvol /dev/$ubidev -N rootfs $root_size_param; then 180 echo "cannot create rootfs volume" 181 return 1; 182 fi 183 184 # create rootfs_data for non-ubifs rootfs 185 if [ "$rootfs_type" != "ubifs" ]; then 186 if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then 187 echo "cannot initialize rootfs_data volume" 188 return 1 189 fi 190 fi 191 sync 192 return 0 193} 194 195nand_do_upgrade_success() { 196 local conf_tar="/tmp/sysupgrade.tgz" 197 198 sync 199 [ -f "$conf_tar" ] && nand_restore_config "$conf_tar" 200 echo "sysupgrade successful" 201 reboot -f 202} 203 204# Flash the UBI image to MTD partition 205nand_upgrade_ubinized() { 206 local ubi_file="$1" 207 local mtdnum="$(find_mtd_index "$CI_UBIPART")" 208 209 [ ! "$mtdnum" ] && { 210 CI_UBIPART="rootfs" 211 mtdnum="$(find_mtd_index "$CI_UBIPART")" 212 } 213 214 if [ ! "$mtdnum" ]; then 215 echo "cannot find mtd device $CI_UBIPART" 216 reboot -f 217 fi 218 219 local mtddev="/dev/mtd${mtdnum}" 220 ubidetach -p "${mtddev}" || true 221 sync 222 ubiformat "${mtddev}" -y -f "${ubi_file}" 223 ubiattach -p "${mtddev}" 224 nand_do_upgrade_success 225} 226 227# Write the UBIFS image to UBI volume 228nand_upgrade_ubifs() { 229 local rootfs_length=`(cat $1 | wc -c) 2> /dev/null` 230 231 nand_upgrade_prepare_ubi "$rootfs_length" "ubifs" "0" "0" 232 233 local ubidev="$( nand_find_ubi "$CI_UBIPART" )" 234 local root_ubivol="$(nand_find_volume $ubidev rootfs)" 235 ubiupdatevol /dev/$root_ubivol -s $rootfs_length $1 236 237 nand_do_upgrade_success 238} 239 240nand_upgrade_tar() { 241 local tar_file="$1" 242 local board_name="$(cat /tmp/sysinfo/board_name)" 243 local kernel_mtd="$(find_mtd_index $CI_KERNPART)" 244 245 local kernel_length=`(tar xf $tar_file sysupgrade-$board_name/kernel -O | wc -c) 2> /dev/null` 246 local rootfs_length=`(tar xf $tar_file sysupgrade-$board_name/root -O | wc -c) 2> /dev/null` 247 248 local rootfs_type="$(identify_tar "$tar_file" sysupgrade-$board_name/root)" 249 250 local has_kernel=1 251 local has_env=0 252 253 [ "$kernel_length" != 0 -a -n "$kernel_mtd" ] && { 254 tar xf $tar_file sysupgrade-$board_name/kernel -O | mtd write - $CI_KERNPART 255 } 256 [ "$kernel_length" = 0 -o ! -z "$kernel_mtd" ] && has_kernel=0 257 258 nand_upgrade_prepare_ubi "$rootfs_length" "$rootfs_type" "$has_kernel" "$has_env" 259 260 local ubidev="$( nand_find_ubi "$CI_UBIPART" )" 261 [ "$has_kernel" = "1" ] && { 262 local kern_ubivol="$(nand_find_volume $ubidev kernel)" 263 tar xf $tar_file sysupgrade-$board_name/kernel -O | \ 264 ubiupdatevol /dev/$kern_ubivol -s $kernel_length - 265 } 266 267 local root_ubivol="$(nand_find_volume $ubidev rootfs)" 268 tar xf $tar_file sysupgrade-$board_name/root -O | \ 269 ubiupdatevol /dev/$root_ubivol -s $rootfs_length - 270 271 nand_do_upgrade_success 272} 273 274# Recognize type of passed file and start the upgrade process 275nand_do_upgrade_stage2() { 276 local file_type=$(identify $1) 277 278 if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then 279 platform_nand_pre_upgrade "$1" 280 fi 281 282 [ ! "$(find_mtd_index "$CI_UBIPART")" ] && CI_UBIPART="rootfs" 283 284 case "$file_type" in 285 "ubi") nand_upgrade_ubinized $1;; 286 "ubifs") nand_upgrade_ubifs $1;; 287 *) nand_upgrade_tar $1;; 288 esac 289} 290 291nand_upgrade_stage2() { 292 [ $1 = "nand" ] && { 293 [ -f "$2" ] && { 294 touch /tmp/sysupgrade 295 296 killall -9 telnetd 297 killall -9 dropbear 298 killall -9 ash 299 300 kill_remaining TERM 301 sleep 3 302 kill_remaining KILL 303 304 sleep 1 305 306 if [ -n "$(rootfs_type)" ]; then 307 v "Switching to ramdisk..." 308 run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2" 309 else 310 nand_do_upgrade_stage2 $2 311 fi 312 return 0 313 } 314 echo "Nand upgrade failed" 315 exit 1 316 } 317} 318 319nand_upgrade_stage1() { 320 [ -f /tmp/sysupgrade-nand-path ] && { 321 path="$(cat /tmp/sysupgrade-nand-path)" 322 [ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] && 323 rm $CONF_TAR 324 325 ubus call system nandupgrade "{\"path\": \"$path\" }" 326 exit 0 327 } 328} 329 330# Check if passed file is a valid one for NAND sysupgrade. Currently it accepts 331# 3 types of files: 332# 1) UBI - should contain an ubinized image, header is checked for the proper 333# MAGIC 334# 2) UBIFS - should contain UBIFS partition that will replace "rootfs" volume, 335# header is checked for the proper MAGIC 336# 3) TAR - archive has to include "sysupgrade-BOARD" directory with a non-empty 337# "CONTROL" file (at this point its content isn't verified) 338# 339# You usually want to call this function in platform_check_image. 340# 341# $(1): board name, used in case of passing TAR file 342# $(2): file to be checked 343nand_do_platform_check() { 344 local board_name="$1" 345 local tar_file="$2" 346 local control_length=`(tar xf $tar_file sysupgrade-$board_name/CONTROL -O | wc -c) 2> /dev/null` 347 local file_type="$(identify $2)" 348 349 [ "$control_length" = 0 -a "$file_type" != "ubi" -a "$file_type" != "ubifs" ] && { 350 echo "Invalid sysupgrade file." 351 return 1 352 } 353 354 return 0 355} 356 357# Start NAND upgrade process 358# 359# $(1): file to be used for upgrade 360nand_do_upgrade() { 361 echo -n $1 > /tmp/sysupgrade-nand-path 362 cp /sbin/upgraded /tmp/ 363 nand_upgrade_stage1 364} 365