4aeeead303
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
250 lines
5.9 KiB
Bash
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
|
|
}
|
|
}
|