7d1a55db0c4cba97e1bbe7b132fbe2f9834b44e9
[openwrt.git] / package / system / procd / files / nand.sh
1 #!/bin/sh
2 # Copyright (C) 2014 OpenWrt.org
3 #
4
5 . /lib/functions.sh
6
7 # combined-image uses 64k blocks
8 CI_BLKSZ=65536
9 # 'data' partition on NAND contains UBI
10 CI_UBIPART="ubi"
11
12 nand_find_volume() {
13         local ubidevdir ubivoldir
14         ubidevdir="/sys/devices/virtual/ubi/$1"
15         [ ! -d "$ubidevdir" ] && return 1
16         for ubivoldir in $ubidevdir/${1}_*; do
17                 [ ! -d "$ubivoldir" ] && continue
18                 if [ "$( cat $ubivoldir/name )" = "$2" ]; then
19                         basename $ubivoldir
20                         return 0
21                 fi
22         done
23 }
24
25 nand_find_ubi() {
26         local ubidevdir ubidev mtdnum
27         mtdnum="$( find_mtd_index $1 )"
28         [ ! "$mtdnum" ] && return 1
29         for ubidevdir in /sys/devices/virtual/ubi/ubi*; do
30                 [ ! -d "$ubidevdir" ] && continue
31                 cmtdnum="$( cat $ubidevdir/mtd_num )"
32                 [ ! "$mtdnum" ] && continue
33                 if [ "$mtdnum" = "$cmtdnum" ]; then
34                         ubidev=$( basename $ubidevdir )
35                         echo $ubidev
36                         return 0
37                 fi
38         done
39 }
40
41 nand_restore_config() {
42         sync
43         local ubidev=$( nand_find_ubi $CI_UBIPART )
44         local ubivol="$( nand_find_volume $ubidev rootfs_data )"
45         [ ! "$ubivol" ] &&
46                 ubivol="$( nand_find_volume $ubidev rootfs )"
47         mkdir /tmp/new_root
48         if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
49                 echo "mounting ubifs $ubivol failed"
50                 rmdir /tmp/new_root
51                 return 1
52         fi
53         mv "$1" "/tmp/new_root/sysupgrade.tgz"
54         umount /tmp/new_root
55         sync
56         rmdir /tmp/new_root
57 }
58
59 nand_upgrade_ubinized() {
60         local upgrade_image="$1"
61         local conf_tar="$2"
62         local save_config="$3"
63         local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
64         if [ ! "$mtdnum" ]; then
65                 echo "cannot find mtd device $CI_UBIPART"
66                 return 1;
67         fi
68         local mtddev="/dev/mtd${mtdnum}"
69         ubidetach -p "${mtddev}" || true
70         sync
71         ubiformat "${mtddev}" -y -f "$upgrade_image"
72         ubiattach -p "${mtddev}"
73         sync
74         if [ -f "$conf_tar" -a "$save_config" -eq 1 ]; then
75                 nand_restore_config "$conf_tar"
76         fi
77         return 0;
78 }
79
80 # get the first 4 bytes (magic) of a given file starting at offset in hex format
81 get_magic_long_at() {
82         dd if="$2" skip=$1 bs=$CI_BLKSZ count=1 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
83 }
84
85 identify() {
86         local block;
87         local magic=$( get_magic_long_at ${2:-0} "$1" )
88         case "$magic" in
89                 "55424923")
90                         echo "ubi"
91                         ;;
92                 "31181006")
93                         echo "ubifs"
94                         ;;
95                 "68737173")
96                         echo "squashfs"
97                         ;;
98                 "d00dfeed")
99                         echo "fit"
100                         ;;
101                 "4349"*)
102                         echo "combined"
103                         ;;
104                 *)
105                         echo "unknown $magic"
106                         ;;
107         esac
108 }
109
110 nand_upgrade_combined_ubi() {
111         local kernel_image="$1"
112         local kernel_length=0
113         local rootfs_image="$2"
114         local rootfs_length=`ls -la $rootfs_image  | awk '{ print $5}')`
115         local conf_tar="$3"
116         local has_env="${4:-0}"
117
118         local root_fs="$( identify "$rootfs_image" )"
119         local mtdnum="$( find_mtd_index "$CI_UBIPART" )"
120         local has_kernel=0
121         
122         [ -z "$kernel_image" ] || {
123                 has_kernel=1 
124                 kernel_length=`ls -la $kernel_image  | awk '{ print $5}')`
125                 echo "kernel length $kernel_length"
126         }
127         [ "$has_kernel" = 0 ] || echo "kernel is inside ubi"
128         echo "rootfs type $root_fs, length $rootfs_length"
129
130         if [ ! "$mtdnum" ]; then
131                 echo "cannot find ubi mtd partition $CI_UBIPART"
132                 return 1
133         fi
134         local ubidev="$( nand_find_ubi "$CI_UBIPART" )"
135         if [ ! "$ubidev" ]; then
136                 ubiattach -m "$mtdnum"
137                 sync
138                 ubidev="$( nand_find_ubi "$CI_UBIPART" )"
139         fi
140         if [ ! "$ubidev" ]; then
141                 ubiformat /dev/mtd$mtdnum -y
142                 ubiattach -m "$mtdnum"
143                 sync
144                 ubidev="$( nand_find_ubi "$CI_UBIPART" )"
145                 [ -z "$has_env" ] || {
146                         ubimkvol /dev/$ubidev -n 0 -N ubootenv -s 1MiB
147                         ubimkvol /dev/$ubidev -n 1 -N ubootenv2 -s 1MiB
148                 }
149         fi
150         local kern_ubivol="$( nand_find_volume $ubidev kernel )"
151         local root_ubivol="$( nand_find_volume $ubidev rootfs )"
152         local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
153
154         # remove ubiblock device of rootfs
155         local root_ubiblk="ubiblock${root_ubivol:3}"
156         if [ "$root_ubivol" -a -e "/dev/$root_ubiblk" ]; then
157                 echo "removing $root_ubiblk"
158                 if ! ubiblock -r /dev/$root_ubivol; then
159                         echo "cannot remove $root_ubiblk"
160                         return 1;
161                 fi
162         fi
163
164         # kill volumes
165         if [ "$kern_ubivol" ]; then
166                 ubirmvol /dev/$ubidev -N kernel || true
167         fi
168         if [ "$root_ubivol" ]; then
169                 ubirmvol /dev/$ubidev -N rootfs || true
170         fi
171         if [ "$data_ubivol" ]; then
172                 ubirmvol /dev/$ubidev -N rootfs_data || true
173         fi
174
175         # update kernel
176         if [ "$has_kernel" = "1" ]; then
177                 if ! ubimkvol /dev/$ubidev -N kernel -s $kernel_length; then
178                         echo "cannot create kernel volume"
179                         return 1;
180                 fi
181         fi
182
183         # update rootfs
184         local root_size_param
185         if [ "$root_fs" = "ubifs" ]; then
186                 root_size_param="-m"
187         else
188                 root_size_param="-s $rootfs_length"
189         fi
190         if ! ubimkvol /dev/$ubidev -N rootfs $root_size_param; then
191                 echo "cannot create rootfs volume"
192                 return 1;
193         fi
194
195         # create rootfs_data for non-ubifs rootfs
196         if [ "$root_fs" != "ubifs" ]; then
197                 if ! ubimkvol /dev/$ubidev -N rootfs_data -m; then
198                         echo "cannot initialize rootfs_data volume"
199                         return 1
200                 fi
201         fi
202         sync
203
204         if [ "$has_kernel" = "1" ]; then
205                 local kern_ubivol="$( nand_find_volume $ubidev kernel )"
206                 ubiupdatevol /dev/$kern_ubivol -s $kernel_length $kernel_image
207         fi
208
209         local root_ubivol="$( nand_find_volume $ubidev rootfs )"
210         ubiupdatevol /dev/$root_ubivol -s $rootfs_length $rootfs_image
211         if [ -f "$conf_tar" ]; then
212                 nand_restore_config "$conf_tar"
213         fi
214         echo "sysupgrade successfull"
215         return 0
216 }
217
218 nand_do_upgrade_stage1() {
219         local board_name="$1"
220         local tar_file="$2"
221         local kernel_file=""
222         local kernel_file=""
223
224         tar xzf $tar_file -C /tmp/
225         [ -f "/tmp/sysupgrade-$board_name/CONTROL" ] || {
226                 echo "failed to find /tmp/sysupgrade-$board_name/CONTROL"
227                 return 1
228         }
229
230         kernel_file=/tmp/sysupgrade-$board_name/kernel
231         [ -f "$kernel_file" ] || {
232                 echo "$kernel_file is missing"
233                 return 1
234         }
235
236         rootfs_file=/tmp/sysupgrade-$board_name/root
237         [ -f "$rootfs_file" ] || {
238                 echo "$rootfs_file is missing"
239                 return 1
240         }
241         
242         echo -n /tmp/sysupgrade-$board_name > /tmp/sysupgrade-nand-folder
243         cp /sbin/upgraded /tmp/
244
245         return 0
246 }
247
248 nand_do_upgrade_stage2() {
249         rootfs_file=$1/root
250         kernel_file=$1/kernel
251         config_file=$1/config
252
253         [ -f $config_file ] || config_file=""
254
255         . $1/CONTROL
256
257         [ "$UBI_KERNEL" = "1" ] || {
258                 mtd write $kernel_file kernel
259                 kernel_file=""
260         }
261         nand_upgrade_combined_ubi "$kernel_file" "$rootfs_file" "$conf_tar" "$UBI_ENV"
262         reboot -f
263 }
264
265 nand_do_upgrade() {
266         [ $1 = "nand" ] && {
267                 [ -d "$2" ] && {
268                         touch /tmp/sysupgrade
269
270                         killall -9 telnetd
271                         killall -9 dropbear
272                         killall -9 ash
273
274                         kill_remaining TERM
275                         sleep 3
276                         kill_remaining KILL
277
278                         sleep 1
279
280                         if [ -n "$(rootfs_type)" ]; then
281                                 v "Switching to ramdisk..."
282                                 run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2"
283                         else
284                                 nand_do_upgrade_stage2 $2
285                         fi
286                         return 0
287                 }
288                 echo "Nand upgrade failed"
289                 exit 1
290         }
291 }
292
293 nand_upgrade_stage1() {
294         [ -f /tmp/sysupgrade-nand-folder ] && {
295                 folder="$(cat /tmp/sysupgrade-nand-folder)"
296                 [ "$SAVE_CONFIG" = 1 -a -f "$CONF_TAR" ] &&
297                         cp $CONF_TAR $folder/config
298
299                 ubus call system nandupgrade "{\"folder\": \"$folder\" }"
300                 exit 0
301         }
302 }
303 append sysupgrade_pre_upgrade nand_upgrade_stage1