common.sh 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. RAM_ROOT=/tmp/root
  2. export BACKUP_FILE=sysupgrade.tgz # file extracted by preinit
  3. [ -x /usr/bin/ldd ] || ldd() { LD_TRACE_LOADED_OBJECTS=1 $*; }
  4. libs() { ldd $* 2>/dev/null | sed -E 's/(.* => )?(.*) .*/\2/'; }
  5. install_file() { # <file> [ <file> ... ]
  6. local target dest dir
  7. for file in "$@"; do
  8. if [ -L "$file" ]; then
  9. target="$(readlink -f "$file")"
  10. dest="$RAM_ROOT/$file"
  11. [ ! -f "$dest" ] && {
  12. dir="$(dirname "$dest")"
  13. mkdir -p "$dir"
  14. ln -s "$target" "$dest"
  15. }
  16. file="$target"
  17. fi
  18. dest="$RAM_ROOT/$file"
  19. [ -f "$file" -a ! -f "$dest" ] && {
  20. dir="$(dirname "$dest")"
  21. mkdir -p "$dir"
  22. cp "$file" "$dest"
  23. }
  24. done
  25. }
  26. install_bin() {
  27. local src files
  28. src=$1
  29. files=$1
  30. [ -x "$src" ] && files="$src $(libs $src)"
  31. install_file $files
  32. }
  33. run_hooks() {
  34. local arg="$1"; shift
  35. for func in "$@"; do
  36. eval "$func $arg"
  37. done
  38. }
  39. ask_bool() {
  40. local default="$1"; shift;
  41. local answer="$default"
  42. [ "$INTERACTIVE" -eq 1 ] && {
  43. case "$default" in
  44. 0) echo -n "$* (y/N): ";;
  45. *) echo -n "$* (Y/n): ";;
  46. esac
  47. read answer
  48. case "$answer" in
  49. y*) answer=1;;
  50. n*) answer=0;;
  51. *) answer="$default";;
  52. esac
  53. }
  54. [ "$answer" -gt 0 ]
  55. }
  56. _v() {
  57. [ -n "$VERBOSE" ] && [ "$VERBOSE" -ge 1 ] && echo "$*" >&2
  58. }
  59. _vn() {
  60. [ -n "$VERBOSE" ] && [ "$VERBOSE" -ge 1 ] && echo -n "$*" >&2
  61. }
  62. v() {
  63. _v "$(date) upgrade: $@"
  64. }
  65. vn() {
  66. _vn "$(date) upgrade: $@"
  67. }
  68. json_string() {
  69. local v="$1"
  70. v="${v//\\/\\\\}"
  71. v="${v//\"/\\\"}"
  72. echo "\"$v\""
  73. }
  74. rootfs_type() {
  75. /bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }'
  76. }
  77. get_image() { # <source> [ <command> ]
  78. local from="$1"
  79. local cmd="$2"
  80. if [ -z "$cmd" ]; then
  81. local magic="$(dd if="$from" bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
  82. case "$magic" in
  83. 1f8b) cmd="zcat";;
  84. 425a) cmd="bzcat";;
  85. *) cmd="cat";;
  86. esac
  87. fi
  88. $cmd <"$from"
  89. }
  90. get_image_dd() {
  91. local from="$1"; shift
  92. (
  93. exec 3>&2
  94. ( exec 3>&2; get_image "$from" 2>&1 1>&3 | grep -v -F ' Broken pipe' ) 2>&1 1>&3 \
  95. | ( exec 3>&2; dd "$@" 2>&1 1>&3 | grep -v -E ' records (in|out)') 2>&1 1>&3
  96. exec 3>&-
  97. )
  98. }
  99. get_magic_word() {
  100. (get_image "$@" | dd bs=2 count=1 | hexdump -v -n 2 -e '1/1 "%02x"') 2>/dev/null
  101. }
  102. get_magic_long() {
  103. (get_image "$@" | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2>/dev/null
  104. }
  105. get_magic_gpt() {
  106. (get_image "$@" | dd bs=8 count=1 skip=64) 2>/dev/null
  107. }
  108. get_magic_vfat() {
  109. (get_image "$@" | dd bs=3 count=1 skip=18) 2>/dev/null
  110. }
  111. get_magic_fat32() {
  112. (get_image "$@" | dd bs=1 count=5 skip=82) 2>/dev/null
  113. }
  114. part_magic_efi() {
  115. local magic=$(get_magic_gpt "$@")
  116. [ "$magic" = "EFI PART" ]
  117. }
  118. part_magic_fat() {
  119. local magic=$(get_magic_vfat "$@")
  120. local magic_fat32=$(get_magic_fat32 "$@")
  121. [ "$magic" = "FAT" ] || [ "$magic_fat32" = "FAT32" ]
  122. }
  123. export_bootdevice() {
  124. local cmdline bootdisk rootpart uuid blockdev uevent line class
  125. local MAJOR MINOR DEVNAME DEVTYPE
  126. if read cmdline < /proc/cmdline; then
  127. case "$cmdline" in
  128. *root=*)
  129. rootpart="${cmdline##*root=}"
  130. rootpart="${rootpart%% *}"
  131. ;;
  132. esac
  133. case "$bootdisk" in
  134. /dev/*)
  135. uevent="/sys/class/block/${bootdisk##*/}/uevent"
  136. ;;
  137. esac
  138. case "$rootpart" in
  139. 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]-[a-f0-9][a-f0-9])
  140. uuid="${rootpart#PARTUUID=}"
  141. uuid="${uuid%-[a-f0-9][a-f0-9]}"
  142. for blockdev in $(find /dev -type b); do
  143. set -- $(dd if=$blockdev bs=1 skip=440 count=4 2>/dev/null | hexdump -v -e '4/1 "%02x "')
  144. if [ "$4$3$2$1" = "$uuid" ]; then
  145. uevent="/sys/class/block/${blockdev##*/}/uevent"
  146. break
  147. fi
  148. done
  149. ;;
  150. PARTUUID=????????-????-????-????-??????????02)
  151. uuid="${rootpart#PARTUUID=}"
  152. uuid="${uuid%02}00"
  153. for disk in $(find /dev -type b); do
  154. set -- $(dd if=$disk bs=1 skip=568 count=16 2>/dev/null | hexdump -v -e '8/1 "%02x "" "2/1 "%02x""-"6/1 "%02x"')
  155. if [ "$4$3$2$1-$6$5-$8$7-$9" = "$uuid" ]; then
  156. uevent="/sys/class/block/${disk##*/}/uevent"
  157. break
  158. fi
  159. done
  160. ;;
  161. /dev/*)
  162. uevent="/sys/class/block/${rootpart##*/}/../uevent"
  163. ;;
  164. 0x[a-f0-9][a-f0-9][a-f0-9] | 0x[a-f0-9][a-f0-9][a-f0-9][a-f0-9] | \
  165. [a-f0-9][a-f0-9][a-f0-9] | [a-f0-9][a-f0-9][a-f0-9][a-f0-9])
  166. rootpart=0x${rootpart#0x}
  167. for class in /sys/class/block/*; do
  168. while read line; do
  169. export -n "$line"
  170. done < "$class/uevent"
  171. if [ $((rootpart/256)) = $MAJOR -a $((rootpart%256)) = $MINOR ]; then
  172. uevent="$class/../uevent"
  173. fi
  174. done
  175. ;;
  176. esac
  177. if [ -e "$uevent" ]; then
  178. while read line; do
  179. export -n "$line"
  180. done < "$uevent"
  181. export BOOTDEV_MAJOR=$MAJOR
  182. export BOOTDEV_MINOR=$MINOR
  183. return 0
  184. fi
  185. fi
  186. return 1
  187. }
  188. export_partdevice() {
  189. local var="$1" offset="$2"
  190. local uevent line MAJOR MINOR DEVNAME DEVTYPE
  191. for uevent in /sys/class/block/*/uevent; do
  192. while read line; do
  193. export -n "$line"
  194. done < "$uevent"
  195. if [ $BOOTDEV_MAJOR = $MAJOR -a $(($BOOTDEV_MINOR + $offset)) = $MINOR -a -b "/dev/$DEVNAME" ]; then
  196. export "$var=$DEVNAME"
  197. return 0
  198. fi
  199. done
  200. return 1
  201. }
  202. hex_le32_to_cpu() {
  203. [ "$(echo 01 | hexdump -v -n 2 -e '/2 "%x"')" = "3031" ] && {
  204. echo "${1:0:2}${1:8:2}${1:6:2}${1:4:2}${1:2:2}"
  205. return
  206. }
  207. echo "$@"
  208. }
  209. get_partitions() { # <device> <filename>
  210. local disk="$1"
  211. local filename="$2"
  212. if [ -b "$disk" -o -f "$disk" ]; then
  213. v "Reading partition table from $filename..."
  214. local magic=$(dd if="$disk" bs=2 count=1 skip=255 2>/dev/null)
  215. if [ "$magic" != $'\x55\xAA' ]; then
  216. v "Invalid partition table on $disk"
  217. exit
  218. fi
  219. rm -f "/tmp/partmap.$filename"
  220. local part
  221. part_magic_efi "$disk" && {
  222. #export_partdevice will fail when partition number is greater than 15, as
  223. #the partition major device number is not equal to the disk major device number
  224. for part in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
  225. set -- $(hexdump -v -n 48 -s "$((0x380 + $part * 0x80))" -e '4/4 "%08x"" "4/4 "%08x"" "4/4 "0x%08X "' "$disk")
  226. local type="$1"
  227. local lba="$(( $(hex_le32_to_cpu $4) * 0x100000000 + $(hex_le32_to_cpu $3) ))"
  228. local end="$(( $(hex_le32_to_cpu $6) * 0x100000000 + $(hex_le32_to_cpu $5) ))"
  229. local num="$(( $end - $lba ))"
  230. [ "$type" = "00000000000000000000000000000000" ] && continue
  231. printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename"
  232. done
  233. } || {
  234. for part in 1 2 3 4; do
  235. set -- $(hexdump -v -n 12 -s "$((0x1B2 + $part * 16))" -e '3/4 "0x%08X "' "$disk")
  236. local type="$(( $(hex_le32_to_cpu $1) % 256))"
  237. local lba="$(( $(hex_le32_to_cpu $2) ))"
  238. local num="$(( $(hex_le32_to_cpu $3) ))"
  239. [ $type -gt 0 ] || continue
  240. printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename"
  241. done
  242. }
  243. fi
  244. }
  245. indicate_upgrade() {
  246. . /etc/diag.sh
  247. set_state upgrade
  248. }
  249. # Flash firmware to MTD partition
  250. #
  251. # $(1): path to image
  252. # $(2): (optional) pipe command to extract firmware, e.g. dd bs=n skip=m
  253. default_do_upgrade() {
  254. sync
  255. echo 3 > /proc/sys/vm/drop_caches
  256. if [ -n "$UPGRADE_BACKUP" ]; then
  257. get_image "$1" "$2" | mtd $MTD_ARGS $MTD_CONFIG_ARGS -j "$UPGRADE_BACKUP" write - "${PART_NAME:-image}"
  258. else
  259. get_image "$1" "$2" | mtd $MTD_ARGS write - "${PART_NAME:-image}"
  260. fi
  261. [ $? -ne 0 ] && exit 1
  262. }