openwrt/package/base-files/files/lib/upgrade/common.sh
Matthias Schiffer 438dcbfe74
base-files: automatically handle paths and symlinks for RAMFS_COPY_BIN
Depending on busybox applet selection, paths of basic utiilties may differ,
and may not work as symlinks to busybox. Simply using whatever binary is
found in PATH and detecting symlinks automatically is more robust and
easier to maintain.

The list of binaries is also slightly cleaned up and duplicates are
removed.

Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
2017-07-11 17:26:32 +02:00

239 lines
4.7 KiB
Bash

#!/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() { # <file> [ <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() { # <source> [ <command> ]
local from="$1"
local cat="$2"
if [ -z "$cat" ]; then
local magic="$(dd if="$from" bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
case "$magic" in
1f8b) cat="zcat";;
425a) cat="bzcat";;
*) cat="cat";;
esac
fi
$cat "$from" 2>/dev/null
}
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
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
. "$uevent"
export BOOTDEV_MAJOR=$MAJOR
export BOOTDEV_MINOR=$MINOR
return 0
fi
fi
return 1
}
export_partdevice() {
local var="$1" offset="$2"
local uevent MAJOR MINOR DEVNAME DEVTYPE
for uevent in /sys/class/block/*/uevent; do
. "$uevent"
if [ $BOOTDEV_MAJOR = $MAJOR -a $(($BOOTDEV_MINOR + $offset)) = $MINOR -a -b "/dev/$DEVNAME" ]; then
export "$var=$DEVNAME"
return 0
fi
done
return 1
}
get_partitions() { # <device> <filename>
local disk="$1"
local filename="$2"
if [ -b "$disk" -o -f "$disk" ]; then
v "Reading partition table from $filename..."
local magic="$(hexdump -v -n 2 -s 0x1FE -e '1/2 "0x%04X"' "$disk")"
if [ "$magic" != 0xAA55 ]; 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="$(($1 % 256))"
local lba="$(($2))"
local num="$(($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
}
# 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_CONFIG_ARGS -j "$CONF_TAR" write - "${PART_NAME:-image}"
else
get_image "$1" "$2" | mtd write - "${PART_NAME:-image}"
fi
}
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
}