52d28c1140
The staged sysupgrade allows to properly unmount the rootfs before writing the new partitions. This will fix upgrades losing configuration when parition sizes change on x86 and similar image types.
477 lines
12 KiB
Diff
477 lines
12 KiB
Diff
From: Matthias Schiffer <mschiffer@universe-factory.net>
|
|
Date: Sat, 22 Apr 2017 00:54:50 +0200
|
|
Subject: base-files: always use staged sysupgrade
|
|
|
|
Support for the -d and -p options is dropped; it may be added again at some
|
|
point by adding these flags to the ubus sysupgrade call.
|
|
|
|
A downside of this is that we get a lot less information about the progress
|
|
of the upgrade: as soon as the actual upgrade starts, all shell sessions
|
|
are killed to allow unmounting the root filesystem.
|
|
|
|
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
|
|
|
|
diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh
|
|
index e3519ca2cb496ff0835a9ef87da7faf217a07964..17248c2b1decd6f92558fb89601238b55fd0f0d6 100644
|
|
--- a/package/base-files/files/lib/upgrade/common.sh
|
|
+++ b/package/base-files/files/lib/upgrade/common.sh
|
|
@@ -56,7 +56,6 @@ run_ramfs() { # <command> [...]
|
|
/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \
|
|
/bin/mknod
|
|
|
|
- install_bin /bin/uclient-fetch /bin/wget
|
|
install_bin /sbin/mtd
|
|
install_bin /sbin/mount_root
|
|
install_bin /sbin/snapshot
|
|
@@ -96,51 +95,37 @@ run_ramfs() { # <command> [...]
|
|
exec /bin/busybox ash -c "$*"
|
|
}
|
|
|
|
-kill_remaining() { # [ <signal> ]
|
|
+kill_remaining() { # [ <signal> [ <loop> ] ]
|
|
local sig="${1:-TERM}"
|
|
+ local loop="${2:-0}"
|
|
+ local run=true
|
|
+ local stat
|
|
+
|
|
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*|*relayd*) : ;;
|
|
-
|
|
- # Killable process
|
|
- *)
|
|
- if [ $pid -ne $$ ] && [ $ppid -ne $$ ]; then
|
|
- echo -n "$name "
|
|
- kill -$sig $pid 2>/dev/null
|
|
- fi
|
|
- ;;
|
|
- esac
|
|
- fi
|
|
+ while $run; do
|
|
+ run=false
|
|
+ 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%)}"
|
|
+
|
|
+ # Skip PID1, ourself and our children
|
|
+ [ $pid -ne 1 -a $pid -ne $$ -a $ppid -ne $$ ] || continue
|
|
+
|
|
+ local cmdline
|
|
+ read cmdline < /proc/$pid/cmdline
|
|
+
|
|
+ # Skip kernel threads
|
|
+ [ -n "$cmdline" ] || continue
|
|
+
|
|
+ echo -n "$name "
|
|
+ kill -$sig $pid 2>/dev/null
|
|
+
|
|
+ [ $loop -eq 1 ] && run=true
|
|
+ done
|
|
done
|
|
echo ""
|
|
}
|
|
@@ -175,28 +160,31 @@ 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 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"')"
|
|
+ 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) conc="zcat";;
|
|
- 425a) conc="bzcat";;
|
|
+ 1f8b) cat="zcat";;
|
|
+ 425a) cat="bzcat";;
|
|
+ *) cat="cat";;
|
|
esac
|
|
fi
|
|
|
|
- eval "$cmd \"$from\" 2>/dev/null ${conc:+| $conc}"
|
|
+ $cat "$from" 2>/dev/null
|
|
}
|
|
|
|
get_magic_word() {
|
|
@@ -320,12 +308,14 @@ default_do_upgrade() {
|
|
fi
|
|
}
|
|
|
|
-do_upgrade() {
|
|
+do_upgrade_stage2() {
|
|
v "Performing system upgrade..."
|
|
- if type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
|
|
- platform_do_upgrade "$ARGV"
|
|
+ if [ -n "$do_upgrade" ]; then
|
|
+ $do_upgrade "$IMAGE"
|
|
+ elif type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
|
|
+ platform_do_upgrade "$IMAGE"
|
|
else
|
|
- default_do_upgrade "$ARGV"
|
|
+ default_do_upgrade "$IMAGE"
|
|
fi
|
|
|
|
if [ "$SAVE_CONFIG" -eq 1 ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then
|
|
@@ -333,12 +323,11 @@ do_upgrade() {
|
|
fi
|
|
|
|
v "Upgrade completed"
|
|
- [ -n "$DELAY" ] && sleep "$DELAY"
|
|
- ask_bool 1 "Reboot" && {
|
|
- v "Rebooting system..."
|
|
- umount -a
|
|
- reboot -f
|
|
- sleep 5
|
|
- echo b 2>/dev/null >/proc/sysrq-trigger
|
|
- }
|
|
+ sleep 1
|
|
+
|
|
+ v "Rebooting system..."
|
|
+ umount -a
|
|
+ reboot -f
|
|
+ sleep 5
|
|
+ echo b 2>/dev/null >/proc/sysrq-trigger
|
|
}
|
|
diff --git a/package/base-files/files/lib/upgrade/nand.sh b/package/base-files/files/lib/upgrade/nand.sh
|
|
index 6bd2005344c081df20e5a330a69e49e37225c39f..1e69c8f9657b39adf2a2c33bd9bac9303bcbc3d7 100644
|
|
--- a/package/base-files/files/lib/upgrade/nand.sh
|
|
+++ b/package/base-files/files/lib/upgrade/nand.sh
|
|
@@ -283,7 +283,16 @@ nand_upgrade_tar() {
|
|
}
|
|
|
|
# Recognize type of passed file and start the upgrade process
|
|
-nand_do_upgrade_stage2() {
|
|
+nand_do_upgrade() {
|
|
+ if [ -n "$IS_PRE_UPGRADE" ]; then
|
|
+ # Previously, nand_do_upgrade was called from the platform_pre_upgrade
|
|
+ # hook; this piece of code handles scripts that haven't been
|
|
+ # updated. All scripts should gradually move to call nand_do_upgrade
|
|
+ # from platform_do_upgrade instead.
|
|
+ export do_upgrade=nand_do_upgrade
|
|
+ return
|
|
+ fi
|
|
+
|
|
local file_type=$(identify $1)
|
|
|
|
if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
|
|
@@ -299,45 +308,6 @@ nand_do_upgrade_stage2() {
|
|
esac
|
|
}
|
|
|
|
-nand_upgrade_stage2() {
|
|
- [ $1 = "nand" ] && {
|
|
- [ -f "$2" ] && {
|
|
- touch /tmp/sysupgrade
|
|
-
|
|
- killall -9 telnetd
|
|
- killall -9 dropbear
|
|
- killall -9 ash
|
|
-
|
|
- kill_remaining TERM
|
|
- sleep 3
|
|
- kill_remaining KILL
|
|
-
|
|
- sleep 1
|
|
-
|
|
- if [ -n "$(rootfs_type)" ]; then
|
|
- v "Switching to ramdisk..."
|
|
- run_ramfs ". /lib/functions.sh; include /lib/upgrade; nand_do_upgrade_stage2 $2"
|
|
- else
|
|
- nand_do_upgrade_stage2 $2
|
|
- fi
|
|
- return 0
|
|
- }
|
|
- echo "Nand upgrade failed"
|
|
- exit 1
|
|
- }
|
|
-}
|
|
-
|
|
-nand_upgrade_stage1() {
|
|
- [ -f /tmp/sysupgrade-nand-path ] && {
|
|
- path="$(cat /tmp/sysupgrade-nand-path)"
|
|
- [ "$SAVE_CONFIG" != 1 -a -f "$CONF_TAR" ] &&
|
|
- rm $CONF_TAR
|
|
-
|
|
- ubus call system nandupgrade "{\"prefix\": \"$RAM_ROOT\", \"path\": \"$path\" }"
|
|
- exit 0
|
|
- }
|
|
-}
|
|
-
|
|
# Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
|
|
# 3 types of files:
|
|
# 1) UBI - should contain an ubinized image, header is checked for the proper
|
|
@@ -364,13 +334,3 @@ nand_do_platform_check() {
|
|
|
|
return 0
|
|
}
|
|
-
|
|
-# Start NAND upgrade process
|
|
-#
|
|
-# $(1): file to be used for upgrade
|
|
-nand_do_upgrade() {
|
|
- echo -n $1 > /tmp/sysupgrade-nand-path
|
|
- install_bin /sbin/upgraded
|
|
- ln -s "$RAM_ROOT"/sbin/upgraded /tmp/upgraded
|
|
- nand_upgrade_stage1
|
|
-}
|
|
diff --git a/package/base-files/files/lib/upgrade/stage2 b/package/base-files/files/lib/upgrade/stage2
|
|
new file mode 100755
|
|
index 0000000000000000000000000000000000000000..4e2aa3a23c3bab07a795762a30a4d4f701081934
|
|
--- /dev/null
|
|
+++ b/package/base-files/files/lib/upgrade/stage2
|
|
@@ -0,0 +1,50 @@
|
|
+#!/bin/sh
|
|
+
|
|
+. /lib/functions.sh
|
|
+. /lib/functions/system.sh
|
|
+
|
|
+export IMAGE="$1"
|
|
+COMMAND="$2"
|
|
+
|
|
+export ARGV="$IMAGE"
|
|
+export ARGC=1
|
|
+
|
|
+export SAVE_CONFIG=1
|
|
+export SAVE_PARTITIONS=1
|
|
+
|
|
+export INTERACTIVE=0
|
|
+export VERBOSE=1
|
|
+export CONFFILES=/tmp/sysupgrade.conffiles
|
|
+export CONF_TAR=/tmp/sysupgrade.tgz
|
|
+
|
|
+
|
|
+[ -f "$CONF_TAR" ] || export SAVE_CONFIG=0
|
|
+[ -f /tmp/sysupgrade.always.overwrite.bootdisk.partmap ] && export SAVE_PARTITIONS=0
|
|
+
|
|
+include /lib/upgrade
|
|
+
|
|
+
|
|
+killall -9 telnetd
|
|
+killall -9 dropbear
|
|
+killall -9 ash
|
|
+
|
|
+kill_remaining TERM
|
|
+sleep 3
|
|
+kill_remaining KILL 1
|
|
+
|
|
+sleep 1
|
|
+
|
|
+
|
|
+if [ -n "$IMAGE" ] && type 'platform_pre_upgrade' >/dev/null 2>/dev/null; then
|
|
+ IS_PRE_UPGRADE=1 platform_pre_upgrade "$IMAGE"
|
|
+
|
|
+ # Needs to be unset again because of busybox weirdness ...
|
|
+ IS_PRE_UPGRADE=
|
|
+fi
|
|
+
|
|
+if [ -n "$(rootfs_type)" ]; then
|
|
+ echo "Switching to ramdisk..."
|
|
+ run_ramfs "$COMMAND"
|
|
+else
|
|
+ exec /bin/busybox ash -c "$COMMAND"
|
|
+fi
|
|
diff --git a/package/base-files/files/sbin/sysupgrade b/package/base-files/files/sbin/sysupgrade
|
|
index c095ca81c50c71021af2dc04a561ac22f6b7442b..2d67371ef74b4b970076a069e97f4fd6a1e0bc95 100755
|
|
--- a/package/base-files/files/sbin/sysupgrade
|
|
+++ b/package/base-files/files/sbin/sysupgrade
|
|
@@ -1,4 +1,7 @@
|
|
#!/bin/sh
|
|
+
|
|
+[ "$1" = "nand" ] && exec /lib/upgrade/stage2 "$2" "$3"
|
|
+
|
|
. /lib/functions.sh
|
|
. /lib/functions/system.sh
|
|
|
|
@@ -11,7 +14,6 @@ export VERBOSE=1
|
|
export SAVE_CONFIG=1
|
|
export SAVE_OVERLAY=0
|
|
export SAVE_PARTITIONS=1
|
|
-export DELAY=
|
|
export CONF_IMAGE=
|
|
export CONF_BACKUP_LIST=0
|
|
export CONF_BACKUP=
|
|
@@ -25,7 +27,6 @@ export TEST=0
|
|
while [ -n "$1" ]; do
|
|
case "$1" in
|
|
-i) export INTERACTIVE=1;;
|
|
- -d) export DELAY="$2"; shift;;
|
|
-v) export VERBOSE="$(($VERBOSE + 1))";;
|
|
-q) export VERBOSE="$(($VERBOSE - 1))";;
|
|
-n) export SAVE_CONFIG=0;;
|
|
@@ -50,10 +51,9 @@ done
|
|
export CONFFILES=/tmp/sysupgrade.conffiles
|
|
export CONF_TAR=/tmp/sysupgrade.tgz
|
|
|
|
-export ARGV="$*"
|
|
-export ARGC="$#"
|
|
+IMAGE="$1"
|
|
|
|
-[ -z "$ARGV" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && {
|
|
+[ -z "$IMAGE" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && {
|
|
cat <<EOF
|
|
Usage: $0 [<upgrade-option>...] <image file or URL>
|
|
$0 [-q] [-i] <backup-command> <file>
|
|
@@ -90,7 +90,7 @@ EOF
|
|
exit 1
|
|
}
|
|
|
|
-[ -n "$ARGV" -a -n "$NEED_IMAGE" ] && {
|
|
+[ -n "$IMAGE" -a -n "$NEED_IMAGE" ] && {
|
|
cat <<-EOF
|
|
-b|--create-backup and -r|--restore-backup do not perform a firmware upgrade.
|
|
Do not specify both -b|-r and a firmware image.
|
|
@@ -136,14 +136,13 @@ sysupgrade_pre_upgrade="fwtool_pre_upgrade"
|
|
|
|
include /lib/upgrade
|
|
|
|
-[ "$1" = "nand" ] && nand_upgrade_stage2 $@
|
|
-
|
|
do_save_conffiles() {
|
|
local conf_tar="${1:-$CONF_TAR}"
|
|
|
|
[ -z "$(rootfs_type)" ] && {
|
|
echo "Cannot save config while running from ramdisk."
|
|
ask_bool 0 "Abort" && exit
|
|
+ rm -f "$conf_tar"
|
|
return 0
|
|
}
|
|
run_hooks "$CONFFILES" $sysupgrade_init_conffiles
|
|
@@ -184,8 +183,33 @@ type platform_check_image >/dev/null 2>/dev/null || {
|
|
exit 1
|
|
}
|
|
|
|
+case "$IMAGE" in
|
|
+ http://*)
|
|
+ wget -O/tmp/sysupgrade.img "$IMAGE"
|
|
+ IMAGE=/tmp/sysupgrade.img
|
|
+ ;;
|
|
+esac
|
|
+
|
|
+IMAGE="$(readlink -f "$IMAGE")"
|
|
+
|
|
+case "$IMAGE" in
|
|
+ '')
|
|
+ echo "Image file not found."
|
|
+ exit 1
|
|
+ ;;
|
|
+ /tmp/*) ;;
|
|
+ *)
|
|
+ v "Image not in /tmp, copying..."
|
|
+ cp -f "$IMAGE" /tmp/sysupgrade.img
|
|
+ IMAGE=/tmp/sysupgrade.img
|
|
+ ;;
|
|
+esac
|
|
+
|
|
+export ARGV="$IMAGE"
|
|
+export ARGC=1
|
|
+
|
|
for check in $sysupgrade_image_check; do
|
|
- ( eval "$check \"\$ARGV\"" ) || {
|
|
+ ( $check "$IMAGE" ) || {
|
|
if [ $FORCE -eq 1 ]; then
|
|
echo "Image check '$check' failed but --force given - will update anyway!"
|
|
break
|
|
@@ -211,6 +235,7 @@ elif ask_bool $SAVE_CONFIG "Keep config files over reflash"; then
|
|
[ $TEST -eq 1 ] || do_save_conffiles
|
|
export SAVE_CONFIG=1
|
|
else
|
|
+ [ $TEST -eq 1 ] || rm -f "$CONF_TAR"
|
|
export SAVE_CONFIG=0
|
|
fi
|
|
|
|
@@ -218,28 +243,18 @@ if [ $TEST -eq 1 ]; then
|
|
exit 0
|
|
fi
|
|
|
|
-run_hooks "" $sysupgrade_pre_upgrade
|
|
-
|
|
-# Some platforms/devices may want different sysupgrade process, e.g. without
|
|
-# killing processes yet or calling ubus system upgrade method.
|
|
-# This is needed e.g. on NAND devices where we just want to trigger stage1 at
|
|
-# this point.
|
|
-if type 'platform_pre_upgrade' >/dev/null 2>/dev/null; then
|
|
- platform_pre_upgrade "$ARGV"
|
|
+if [ $SAVE_PARTITIONS -eq 0 ]; then
|
|
+ touch /tmp/sysupgrade.always.overwrite.bootdisk.partmap
|
|
+else
|
|
+ rm -f /tmp/sysupgrade.always.overwrite.bootdisk.partmap
|
|
fi
|
|
|
|
-ubus call system upgrade
|
|
-touch /tmp/sysupgrade
|
|
-
|
|
-if [ ! -f /tmp/failsafe ] ; then
|
|
- kill_remaining TERM
|
|
- sleep 3
|
|
- kill_remaining KILL
|
|
-fi
|
|
+run_hooks "" $sysupgrade_pre_upgrade
|
|
|
|
-if [ -n "$(rootfs_type)" ]; then
|
|
- v "Switching to ramdisk..."
|
|
- run_ramfs '. /lib/functions.sh; include /lib/upgrade; do_upgrade'
|
|
-else
|
|
- do_upgrade
|
|
-fi
|
|
+install_bin /sbin/upgraded
|
|
+v "Commencing upgrade. All shell sessions will be closed now."
|
|
+ubus call system sysupgrade "{
|
|
+ \"prefix\": \"$RAM_ROOT\",
|
|
+ \"path\": $(json_string "$IMAGE"),
|
|
+ \"command\": \". /lib/functions.sh; include /lib/upgrade; do_upgrade_stage2\"
|
|
+}"
|