gluon/patches/lede/0018-base-files-always-use-staged-sysupgrade.patch
Matthias Schiffer 52d28c1140
Backport staged sysupgrade patches
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.
2017-05-30 07:31:37 +02:00

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\"
+}"