fc59bf2323498d332159b00eb7ab443bfe6b147e
[openwrt/openwrt.git] / package / base-files / files / lib / upgrade / common.sh
1 #!/bin/sh
2
3 RAM_ROOT=/tmp/root
4
5 [ -x /usr/bin/ldd ] || ldd() { LD_TRACE_LOADED_OBJECTS=1 $*; }
6 libs() { ldd $* 2>/dev/null | sed -r 's/(.* => )?(.*) .*/\2/'; }
7
8 install_file() { # <file> [ <file> ... ]
9 for file in "$@"; do
10 dest="$RAM_ROOT/$file"
11 [ -f $file -a ! -f $dest ] && {
12 dir="$(dirname $dest)"
13 mkdir -p "$dir"
14 cp $file $dest
15 }
16 done
17 }
18
19 install_bin() { # <file> [ <symlink> ... ]
20 src=$1
21 files=$1
22 [ -x "$src" ] && files="$src $(libs $src)"
23 install_file $files
24 shift
25 for link in "$@"; do {
26 dest="$RAM_ROOT/$link"
27 dir="$(dirname $dest)"
28 mkdir -p "$dir"
29 [ -f "$dest" ] || ln -s $src $dest
30 }; done
31 }
32
33 run_hooks() {
34 local arg="$1"; shift
35 for func in "$@"; do
36 eval "$func $arg"
37 done
38 }
39
40 ask_bool() {
41 local default="$1"; shift;
42 local answer="$default"
43
44 [ "$INTERACTIVE" -eq 1 ] && {
45 case "$default" in
46 0) echo -n "$* (y/N): ";;
47 *) echo -n "$* (Y/n): ";;
48 esac
49 read answer
50 case "$answer" in
51 y*) answer=1;;
52 n*) answer=0;;
53 *) answer="$default";;
54 esac
55 }
56 [ "$answer" -gt 0 ]
57 }
58
59 v() {
60 [ "$VERBOSE" -ge 1 ] && echo "$@"
61 }
62
63 json_string() {
64 local v="$1"
65 v="${v//\\/\\\\}"
66 v="${v//\"/\\\"}"
67 echo "\"$v\""
68 }
69
70 rootfs_type() {
71 /bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }'
72 }
73
74 get_image() { # <source> [ <command> ]
75 local from="$1"
76 local cat="$2"
77
78 if [ -z "$cat" ]; then
79 local magic="$(dd if="$from" bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
80 case "$magic" in
81 1f8b) cat="zcat";;
82 425a) cat="bzcat";;
83 *) cat="cat";;
84 esac
85 fi
86
87 $cat "$from" 2>/dev/null
88 }
89
90 get_magic_word() {
91 (get_image "$@" | dd bs=2 count=1 | hexdump -v -n 2 -e '1/1 "%02x"') 2>/dev/null
92 }
93
94 get_magic_long() {
95 (get_image "$@" | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2>/dev/null
96 }
97
98 export_bootdevice() {
99 local cmdline uuid disk uevent
100 local MAJOR MINOR DEVNAME DEVTYPE
101
102 if read cmdline < /proc/cmdline; then
103 case "$cmdline" in
104 *block2mtd=*)
105 disk="${cmdline##*block2mtd=}"
106 disk="${disk%%,*}"
107 ;;
108 *root=*)
109 disk="${cmdline##*root=}"
110 disk="${disk%% *}"
111 ;;
112 esac
113
114 case "$disk" in
115 PARTUUID=[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]-02)
116 uuid="${disk#PARTUUID=}"
117 uuid="${uuid%-02}"
118 for disk in $(find /dev -type b); do
119 set -- $(dd if=$disk bs=1 skip=440 count=4 2>/dev/null | hexdump -v -e '4/1 "%02x "')
120 if [ "$4$3$2$1" = "$uuid" ]; then
121 uevent="/sys/class/block/${disk##*/}/uevent"
122 break
123 fi
124 done
125 ;;
126 /dev/*)
127 uevent="/sys/class/block/${disk##*/}/uevent"
128 ;;
129 esac
130
131 if [ -e "$uevent" ]; then
132 . "$uevent"
133
134 export BOOTDEV_MAJOR=$MAJOR
135 export BOOTDEV_MINOR=$MINOR
136 return 0
137 fi
138 fi
139
140 return 1
141 }
142
143 export_partdevice() {
144 local var="$1" offset="$2"
145 local uevent MAJOR MINOR DEVNAME DEVTYPE
146
147 for uevent in /sys/class/block/*/uevent; do
148 . "$uevent"
149 if [ $BOOTDEV_MAJOR = $MAJOR -a $(($BOOTDEV_MINOR + $offset)) = $MINOR -a -b "/dev/$DEVNAME" ]; then
150 export "$var=$DEVNAME"
151 return 0
152 fi
153 done
154
155 return 1
156 }
157
158 get_partitions() { # <device> <filename>
159 local disk="$1"
160 local filename="$2"
161
162 if [ -b "$disk" -o -f "$disk" ]; then
163 v "Reading partition table from $filename..."
164
165 local magic="$(hexdump -v -n 2 -s 0x1FE -e '1/2 "0x%04X"' "$disk")"
166 if [ "$magic" != 0xAA55 ]; then
167 v "Invalid partition table on $disk"
168 exit
169 fi
170
171 rm -f "/tmp/partmap.$filename"
172
173 local part
174 for part in 1 2 3 4; do
175 set -- $(hexdump -v -n 12 -s "$((0x1B2 + $part * 16))" -e '3/4 "0x%08X "' "$disk")
176
177 local type="$(($1 % 256))"
178 local lba="$(($2))"
179 local num="$(($3))"
180
181 [ $type -gt 0 ] || continue
182
183 printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename"
184 done
185 fi
186 }
187
188 jffs2_copy_config() {
189 if grep rootfs_data /proc/mtd >/dev/null; then
190 # squashfs+jffs2
191 mtd -e rootfs_data jffs2write "$CONF_TAR" rootfs_data
192 else
193 # jffs2
194 mtd jffs2write "$CONF_TAR" rootfs
195 fi
196 }
197
198 # Flash firmware to MTD partition
199 #
200 # $(1): path to image
201 # $(2): (optional) pipe command to extract firmware, e.g. dd bs=n skip=m
202 default_do_upgrade() {
203 sync
204 if [ "$SAVE_CONFIG" -eq 1 ]; then
205 get_image "$1" "$2" | mtd $MTD_CONFIG_ARGS -j "$CONF_TAR" write - "${PART_NAME:-image}"
206 else
207 get_image "$1" "$2" | mtd write - "${PART_NAME:-image}"
208 fi
209 }
210
211 do_upgrade_stage2() {
212 v "Performing system upgrade..."
213 if [ -n "$do_upgrade" ]; then
214 $do_upgrade "$IMAGE"
215 elif type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
216 platform_do_upgrade "$IMAGE"
217 else
218 default_do_upgrade "$IMAGE"
219 fi
220
221 if [ "$SAVE_CONFIG" -eq 1 ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then
222 platform_copy_config
223 fi
224
225 v "Upgrade completed"
226 sleep 1
227
228 v "Rebooting system..."
229 umount -a
230 reboot -f
231 sleep 5
232 echo b 2>/dev/null >/proc/sysrq-trigger
233 }