nand.sh 8.7 KB

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