openwrtv4/package/base-files/files/lib/upgrade/common.sh
Jo-Philipp Wich 4aeeead303 x86: preserve partition table on sysupgrade
With this patch sysupgrade will write directly to the partitions
instead of to the main disk.  The UUID is copied from the image
to the MBR as well.  This prevents the mbr from being completely
overwritten and losing the partition table.  The -p option has
been added to maintain the original behavior and overwite the
entire disk with the new image.  Tests have been added to ensure
that the image partitions match up with the active partitions.

Signed-off-by: Rob Mosher <nyt-openwrt@countercultured.net>

SVN-Revision: 48682
2016-02-09 12:33:17 +00:00

250 lines
5.9 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> ... ]
for file in "$@"; do
dest="$RAM_ROOT/$file"
[ -f $file -a ! -f $dest ] && {
dir="$(dirname $dest)"
mkdir -p "$dir"
cp $file $dest
}
done
}
install_bin() { # <file> [ <symlink> ... ]
src=$1
files=$1
[ -x "$src" ] && files="$src $(libs $src)"
install_file $files
shift
for link in "$@"; do {
dest="$RAM_ROOT/$link"
dir="$(dirname $dest)"
mkdir -p "$dir"
[ -f "$dest" ] || ln -s $src $dest
}; done
}
supivot() { # <new_root> <old_root>
/bin/mount | grep "on $1 type" 2>&- 1>&- || /bin/mount -o bind $1 $1
mkdir -p $1$2 $1/proc $1/sys $1/dev $1/tmp $1/overlay && \
/bin/mount -o noatime,move /proc $1/proc && \
pivot_root $1 $1$2 || {
/bin/umount -l $1 $1
return 1
}
/bin/mount -o noatime,move $2/sys /sys
/bin/mount -o noatime,move $2/dev /dev
/bin/mount -o noatime,move $2/tmp /tmp
/bin/mount -o noatime,move $2/overlay /overlay 2>&-
return 0
}
run_ramfs() { # <command> [...]
install_bin /bin/busybox /bin/ash /bin/sh /bin/mount /bin/umount \
/sbin/pivot_root /sbin/reboot /bin/sync /bin/dd /bin/grep \
/bin/cp /bin/mv /bin/tar /usr/bin/md5sum "/usr/bin/[" /bin/dd \
/bin/vi /bin/ls /bin/cat /usr/bin/awk /usr/bin/hexdump \
/bin/sleep /bin/zcat /usr/bin/bzcat /usr/bin/printf /usr/bin/wc \
/bin/cut /usr/bin/printf /bin/sync /bin/mkdir /bin/rmdir \
/bin/rm /usr/bin/basename /bin/kill /bin/chmod
install_bin /bin/uclient-fetch /bin/wget
install_bin /sbin/mtd
install_bin /sbin/mount_root
install_bin /sbin/snapshot
install_bin /sbin/snapshot_tool
install_bin /usr/sbin/ubiupdatevol
install_bin /usr/sbin/ubiattach
install_bin /usr/sbin/ubiblock
install_bin /usr/sbin/ubiformat
install_bin /usr/sbin/ubidetach
install_bin /usr/sbin/ubirsvol
install_bin /usr/sbin/ubirmvol
install_bin /usr/sbin/ubimkvol
install_bin /usr/sbin/partx
for file in $RAMFS_COPY_BIN; do
install_bin ${file//:/ }
done
install_file /etc/resolv.conf /lib/*.sh /lib/functions/*.sh /lib/upgrade/*.sh $RAMFS_COPY_DATA
[ -L "/lib64" ] && ln -s /lib $RAM_ROOT/lib64
supivot $RAM_ROOT /mnt || {
echo "Failed to switch over to ramfs. Please reboot."
exit 1
}
/bin/mount -o remount,ro /mnt
/bin/umount -l /mnt
grep /overlay /proc/mounts > /dev/null && {
/bin/mount -o noatime,remount,ro /overlay
/bin/umount -l /overlay
}
# spawn a new shell from ramdisk to reduce the probability of cache issues
exec /bin/busybox ash -c "$*"
}
kill_remaining() { # [ <signal> ]
local sig="${1:-TERM}"
echo -n "Sending $sig to remaining processes ... "
local my_pid=$$
local my_ppid=$(cut -d' ' -f4 /proc/$my_pid/stat)
local my_ppisupgraded=
grep -q upgraded /proc/$my_ppid/cmdline >/dev/null && {
local my_ppisupgraded=1
}
local stat
for stat in /proc/[0-9]*/stat; do
[ -f "$stat" ] || continue
local pid name state ppid rest
read pid name state ppid rest < $stat
name="${name#(}"; name="${name%)}"
local cmdline
read cmdline < /proc/$pid/cmdline
# Skip kernel threads
[ -n "$cmdline" ] || continue
if [ $$ -eq 1 ] || [ $my_ppid -eq 1 ] && [ -n "$my_ppisupgraded" ]; then
# Running as init process, kill everything except me
if [ $pid -ne $$ ] && [ $pid -ne $my_ppid ]; then
echo -n "$name "
kill -$sig $pid 2>/dev/null
fi
else
case "$name" in
# Skip essential services
*procd*|*ash*|*init*|*watchdog*|*ssh*|*dropbear*|*telnet*|*login*|*hostapd*|*wpa_supplicant*|*nas*) : ;;
# Killable process
*)
if [ $pid -ne $$ ] && [ $ppid -ne $$ ]; then
echo -n "$name "
kill -$sig $pid 2>/dev/null
fi
;;
esac
fi
done
echo ""
}
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 "$@"
}
rootfs_type() {
/bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }'
}
get_image() { # <source> [ <command> ]
local from="$1"
local conc="$2"
local cmd
case "$from" in
http://*|ftp://*) cmd="wget -O- -q";;
*) cmd="cat";;
esac
if [ -z "$conc" ]; then
local magic="$(eval $cmd \"$from\" 2>/dev/null | dd bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
case "$magic" in
1f8b) conc="zcat";;
425a) conc="bzcat";;
esac
fi
eval "$cmd \"$from\" 2>/dev/null ${conc:+| $conc}"
}
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
}
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() {
v "Performing system upgrade..."
if type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
platform_do_upgrade "$ARGV"
else
default_do_upgrade "$ARGV"
fi
if [ "$SAVE_CONFIG" -eq 1 ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then
platform_copy_config
fi
v "Upgrade completed"
[ -n "$DELAY" ] && sleep "$DELAY"
ask_bool 1 "Reboot" && {
v "Rebooting system..."
reboot -f
sleep 5
echo b 2>/dev/null >/proc/sysrq-trigger
}
}