#!/bin/sh RAM_ROOT=/tmp/root [ -x /usr/bin/ldd ] || ldd() { LD_TRACE_LOADED_OBJECTS=1 $*; } libs() { ldd $* 2>/dev/null | sed -r 's/(.* => )?(.*) .*/\2/'; } install_file() { # [ ... ] local target dest dir for file in "$@"; do if [ -L "$file" ]; then target="$(readlink -f "$file")" dest="$RAM_ROOT/$file" [ ! -f "$dest" ] && { dir="$(dirname "$dest")" mkdir -p "$dir" ln -s "$target" "$dest" } file="$target" fi dest="$RAM_ROOT/$file" [ -f "$file" -a ! -f "$dest" ] && { dir="$(dirname "$dest")" mkdir -p "$dir" cp "$file" "$dest" } done } install_bin() { local src files src=$1 files=$1 [ -x "$src" ] && files="$src $(libs $src)" install_file $files } run_hooks() { local arg="$1"; shift for func in "$@"; do eval "$func $arg" done } ask_bool() { local default="$1"; shift; local answer="$default" [ "$INTERACTIVE" -eq 1 ] && { case "$default" in 0) echo -n "$* (y/N): ";; *) echo -n "$* (Y/n): ";; esac read answer case "$answer" in y*) answer=1;; n*) answer=0;; *) answer="$default";; esac } [ "$answer" -gt 0 ] } v() { [ "$VERBOSE" -ge 1 ] && echo "$@" } json_string() { local v="$1" v="${v//\\/\\\\}" v="${v//\"/\\\"}" echo "\"$v\"" } rootfs_type() { /bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }' } get_image() { # [ ] local from="$1" local cmd="$2" if [ -z "$cmd" ]; then local magic="$(dd if="$from" bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')" case "$magic" in 1f8b) cmd="zcat";; 425a) cmd="bzcat";; *) cmd="cat";; esac fi cat "$from" 2>/dev/null | $cmd } get_magic_word() { (get_image "$@" | dd bs=2 count=1 | hexdump -v -n 2 -e '1/1 "%02x"') 2>/dev/null } get_magic_long() { (get_image "$@" | dd bs=4 count=1 | hexdump -v -n 4 -e '1/1 "%02x"') 2>/dev/null } export_bootdevice() { local cmdline uuid disk uevent line local MAJOR MINOR DEVNAME DEVTYPE if read cmdline < /proc/cmdline; then case "$cmdline" in *block2mtd=*) disk="${cmdline##*block2mtd=}" disk="${disk%%,*}" ;; *root=*) disk="${cmdline##*root=}" disk="${disk%% *}" ;; esac case "$disk" in 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) uuid="${disk#PARTUUID=}" uuid="${uuid%-02}" for disk in $(find /dev -type b); do set -- $(dd if=$disk bs=1 skip=440 count=4 2>/dev/null | hexdump -v -e '4/1 "%02x "') if [ "$4$3$2$1" = "$uuid" ]; then uevent="/sys/class/block/${disk##*/}/uevent" break fi done ;; /dev/*) uevent="/sys/class/block/${disk##*/}/uevent" ;; esac if [ -e "$uevent" ]; then while read line; do export -n "$line" done < "$uevent" export BOOTDEV_MAJOR=$MAJOR export BOOTDEV_MINOR=$MINOR return 0 fi fi return 1 } export_partdevice() { local var="$1" offset="$2" local uevent line MAJOR MINOR DEVNAME DEVTYPE for uevent in /sys/class/block/*/uevent; do while read line; do export -n "$line" done < "$uevent" if [ $BOOTDEV_MAJOR = $MAJOR -a $(($BOOTDEV_MINOR + $offset)) = $MINOR -a -b "/dev/$DEVNAME" ]; then export "$var=$DEVNAME" return 0 fi done return 1 } hex_le32_to_cpu() { [ "$(echo 01 | hexdump -v -n 2 -e '/2 "%x"')" = "3031" ] && { echo "${1:0:2}${1:8:2}${1:6:2}${1:4:2}${1:2:2}" return } echo "$@" } get_partitions() { # local disk="$1" local filename="$2" if [ -b "$disk" -o -f "$disk" ]; then v "Reading partition table from $filename..." local magic=$(dd if="$disk" bs=2 count=1 skip=255 2>/dev/null) if [ "$magic" != $'\x55\xAA' ]; then v "Invalid partition table on $disk" exit fi rm -f "/tmp/partmap.$filename" local part for part in 1 2 3 4; do set -- $(hexdump -v -n 12 -s "$((0x1B2 + $part * 16))" -e '3/4 "0x%08X "' "$disk") local type="$(( $(hex_le32_to_cpu $1) % 256))" local lba="$(( $(hex_le32_to_cpu $2) ))" local num="$(( $(hex_le32_to_cpu $3) ))" [ $type -gt 0 ] || continue printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename" done fi } jffs2_copy_config() { if grep rootfs_data /proc/mtd >/dev/null; then # squashfs+jffs2 mtd -e rootfs_data jffs2write "$CONF_TAR" rootfs_data else # jffs2 mtd jffs2write "$CONF_TAR" rootfs fi } indicate_upgrade() { . /etc/diag.sh set_state upgrade } # Flash firmware to MTD partition # # $(1): path to image # $(2): (optional) pipe command to extract firmware, e.g. dd bs=n skip=m default_do_upgrade() { sync if [ "$SAVE_CONFIG" -eq 1 ]; then get_image "$1" "$2" | mtd $MTD_ARGS $MTD_CONFIG_ARGS -j "$CONF_TAR" write - "${PART_NAME:-image}" else get_image "$1" "$2" | mtd $MTD_ARGS write - "${PART_NAME:-image}" fi [ $? -ne 0 ] && exit 1 } do_upgrade_stage2() { v "Performing system upgrade..." if [ -n "$do_upgrade" ]; then eval "$do_upgrade" elif type 'platform_do_upgrade' >/dev/null 2>/dev/null; then platform_do_upgrade "$IMAGE" else default_do_upgrade "$IMAGE" fi if [ "$SAVE_CONFIG" -eq 1 ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then platform_copy_config fi v "Upgrade completed" sleep 1 v "Rebooting system..." umount -a reboot -f sleep 5 echo b 2>/dev/null >/proc/sysrq-trigger }