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>
This commit is contained in:
Matthias Schiffer 2017-04-22 00:54:50 +02:00
parent 393817df5d
commit 30f61a34b4
No known key found for this signature in database
GPG key ID: 16EF3F64CB201D9C
4 changed files with 157 additions and 143 deletions

View file

@ -56,7 +56,6 @@ run_ramfs() { # <command> [...]
/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \ /bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find \
/bin/mknod /bin/mknod
install_bin /bin/uclient-fetch /bin/wget
install_bin /sbin/mtd install_bin /sbin/mtd
install_bin /sbin/mount_root install_bin /sbin/mount_root
install_bin /sbin/snapshot install_bin /sbin/snapshot
@ -96,51 +95,37 @@ run_ramfs() { # <command> [...]
exec /bin/busybox ash -c "$*" exec /bin/busybox ash -c "$*"
} }
kill_remaining() { # [ <signal> ] kill_remaining() { # [ <signal> [ <loop> ] ]
local sig="${1:-TERM}" local sig="${1:-TERM}"
local loop="${2:-0}"
local run=true
local stat
echo -n "Sending $sig to remaining processes ... " echo -n "Sending $sig to remaining processes ... "
local my_pid=$$ while $run; do
local my_ppid=$(cut -d' ' -f4 /proc/$my_pid/stat) run=false
local my_ppisupgraded= for stat in /proc/[0-9]*/stat; do
grep -q upgraded /proc/$my_ppid/cmdline >/dev/null && { [ -f "$stat" ] || continue
local my_ppisupgraded=1
}
local stat
for stat in /proc/[0-9]*/stat; do
[ -f "$stat" ] || continue
local pid name state ppid rest local pid name state ppid rest
read pid name state ppid rest < $stat read pid name state ppid rest < $stat
name="${name#(}"; name="${name%)}" name="${name#(}"; name="${name%)}"
local cmdline # Skip PID1, ourself and our children
read cmdline < /proc/$pid/cmdline [ $pid -ne 1 -a $pid -ne $$ -a $ppid -ne $$ ] || continue
# Skip kernel threads local cmdline
[ -n "$cmdline" ] || continue read cmdline < /proc/$pid/cmdline
if [ $$ -eq 1 ] || [ $my_ppid -eq 1 ] && [ -n "$my_ppisupgraded" ]; then # Skip kernel threads
# Running as init process, kill everything except me [ -n "$cmdline" ] || continue
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 echo -n "$name "
*) kill -$sig $pid 2>/dev/null
if [ $pid -ne $$ ] && [ $ppid -ne $$ ]; then
echo -n "$name " [ $loop -eq 1 ] && run=true
kill -$sig $pid 2>/dev/null done
fi
;;
esac
fi
done done
echo "" echo ""
} }
@ -175,28 +160,31 @@ v() {
[ "$VERBOSE" -ge 1 ] && echo "$@" [ "$VERBOSE" -ge 1 ] && echo "$@"
} }
json_string() {
local v="$1"
v="${v//\\/\\\\}"
v="${v//\"/\\\"}"
echo "\"$v\""
}
rootfs_type() { rootfs_type() {
/bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }' /bin/mount | awk '($3 ~ /^\/$/) && ($5 !~ /rootfs/) { print $5 }'
} }
get_image() { # <source> [ <command> ] get_image() { # <source> [ <command> ]
local from="$1" local from="$1"
local conc="$2" local cat="$2"
local cmd
case "$from" in if [ -z "$cat" ]; then
http://*|ftp://*) cmd="wget -O- -q";; local magic="$(dd if="$from" bs=2 count=1 2>/dev/null | hexdump -n 2 -e '1/1 "%02x"')"
*) 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 case "$magic" in
1f8b) conc="zcat";; 1f8b) cat="zcat";;
425a) conc="bzcat";; 425a) cat="bzcat";;
*) cat="cat";;
esac esac
fi fi
eval "$cmd \"$from\" 2>/dev/null ${conc:+| $conc}" $cat "$from" 2>/dev/null
} }
get_magic_word() { get_magic_word() {
@ -320,12 +308,14 @@ default_do_upgrade() {
fi fi
} }
do_upgrade() { do_upgrade_stage2() {
v "Performing system upgrade..." v "Performing system upgrade..."
if type 'platform_do_upgrade' >/dev/null 2>/dev/null; then if [ -n "$do_upgrade" ]; then
platform_do_upgrade "$ARGV" $do_upgrade "$IMAGE"
elif type 'platform_do_upgrade' >/dev/null 2>/dev/null; then
platform_do_upgrade "$IMAGE"
else else
default_do_upgrade "$ARGV" default_do_upgrade "$IMAGE"
fi fi
if [ "$SAVE_CONFIG" -eq 1 ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then if [ "$SAVE_CONFIG" -eq 1 ] && type 'platform_copy_config' >/dev/null 2>/dev/null; then
@ -333,12 +323,11 @@ do_upgrade() {
fi fi
v "Upgrade completed" v "Upgrade completed"
[ -n "$DELAY" ] && sleep "$DELAY" sleep 1
ask_bool 1 "Reboot" && {
v "Rebooting system..." v "Rebooting system..."
umount -a umount -a
reboot -f reboot -f
sleep 5 sleep 5
echo b 2>/dev/null >/proc/sysrq-trigger echo b 2>/dev/null >/proc/sysrq-trigger
}
} }

View file

@ -283,7 +283,16 @@ nand_upgrade_tar() {
} }
# Recognize type of passed file and start the upgrade process # 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) local file_type=$(identify $1)
if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then if type 'platform_nand_pre_upgrade' >/dev/null 2>/dev/null; then
@ -299,45 +308,6 @@ nand_do_upgrade_stage2() {
esac 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 # Check if passed file is a valid one for NAND sysupgrade. Currently it accepts
# 3 types of files: # 3 types of files:
# 1) UBI - should contain an ubinized image, header is checked for the proper # 1) UBI - should contain an ubinized image, header is checked for the proper
@ -364,13 +334,3 @@ nand_do_platform_check() {
return 0 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
}

View file

@ -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

View file

@ -1,4 +1,7 @@
#!/bin/sh #!/bin/sh
[ "$1" = "nand" ] && exec /lib/upgrade/stage2 "$2" "$3"
. /lib/functions.sh . /lib/functions.sh
. /lib/functions/system.sh . /lib/functions/system.sh
@ -11,7 +14,6 @@ export VERBOSE=1
export SAVE_CONFIG=1 export SAVE_CONFIG=1
export SAVE_OVERLAY=0 export SAVE_OVERLAY=0
export SAVE_PARTITIONS=1 export SAVE_PARTITIONS=1
export DELAY=
export CONF_IMAGE= export CONF_IMAGE=
export CONF_BACKUP_LIST=0 export CONF_BACKUP_LIST=0
export CONF_BACKUP= export CONF_BACKUP=
@ -25,7 +27,6 @@ export TEST=0
while [ -n "$1" ]; do while [ -n "$1" ]; do
case "$1" in case "$1" in
-i) export INTERACTIVE=1;; -i) export INTERACTIVE=1;;
-d) export DELAY="$2"; shift;;
-v) export VERBOSE="$(($VERBOSE + 1))";; -v) export VERBOSE="$(($VERBOSE + 1))";;
-q) export VERBOSE="$(($VERBOSE - 1))";; -q) export VERBOSE="$(($VERBOSE - 1))";;
-n) export SAVE_CONFIG=0;; -n) export SAVE_CONFIG=0;;
@ -50,10 +51,9 @@ done
export CONFFILES=/tmp/sysupgrade.conffiles export CONFFILES=/tmp/sysupgrade.conffiles
export CONF_TAR=/tmp/sysupgrade.tgz export CONF_TAR=/tmp/sysupgrade.tgz
export ARGV="$*" IMAGE="$1"
export ARGC="$#"
[ -z "$ARGV" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && { [ -z "$IMAGE" -a -z "$NEED_IMAGE" -o $HELP -gt 0 ] && {
cat <<EOF cat <<EOF
Usage: $0 [<upgrade-option>...] <image file or URL> Usage: $0 [<upgrade-option>...] <image file or URL>
$0 [-q] [-i] <backup-command> <file> $0 [-q] [-i] <backup-command> <file>
@ -90,7 +90,7 @@ EOF
exit 1 exit 1
} }
[ -n "$ARGV" -a -n "$NEED_IMAGE" ] && { [ -n "$IMAGE" -a -n "$NEED_IMAGE" ] && {
cat <<-EOF cat <<-EOF
-b|--create-backup and -r|--restore-backup do not perform a firmware upgrade. -b|--create-backup and -r|--restore-backup do not perform a firmware upgrade.
Do not specify both -b|-r and a firmware image. Do not specify both -b|-r and a firmware image.
@ -136,14 +136,13 @@ sysupgrade_pre_upgrade="fwtool_pre_upgrade"
include /lib/upgrade include /lib/upgrade
[ "$1" = "nand" ] && nand_upgrade_stage2 $@
do_save_conffiles() { do_save_conffiles() {
local conf_tar="${1:-$CONF_TAR}" local conf_tar="${1:-$CONF_TAR}"
[ -z "$(rootfs_type)" ] && { [ -z "$(rootfs_type)" ] && {
echo "Cannot save config while running from ramdisk." echo "Cannot save config while running from ramdisk."
ask_bool 0 "Abort" && exit ask_bool 0 "Abort" && exit
rm -f "$conf_tar"
return 0 return 0
} }
run_hooks "$CONFFILES" $sysupgrade_init_conffiles run_hooks "$CONFFILES" $sysupgrade_init_conffiles
@ -184,8 +183,33 @@ type platform_check_image >/dev/null 2>/dev/null || {
exit 1 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 for check in $sysupgrade_image_check; do
( eval "$check \"\$ARGV\"" ) || { ( $check "$IMAGE" ) || {
if [ $FORCE -eq 1 ]; then if [ $FORCE -eq 1 ]; then
echo "Image check '$check' failed but --force given - will update anyway!" echo "Image check '$check' failed but --force given - will update anyway!"
break break
@ -211,6 +235,7 @@ elif ask_bool $SAVE_CONFIG "Keep config files over reflash"; then
[ $TEST -eq 1 ] || do_save_conffiles [ $TEST -eq 1 ] || do_save_conffiles
export SAVE_CONFIG=1 export SAVE_CONFIG=1
else else
[ $TEST -eq 1 ] || rm -f "$CONF_TAR"
export SAVE_CONFIG=0 export SAVE_CONFIG=0
fi fi
@ -218,28 +243,18 @@ if [ $TEST -eq 1 ]; then
exit 0 exit 0
fi fi
if [ $SAVE_PARTITIONS -eq 0 ]; then
touch /tmp/sysupgrade.always.overwrite.bootdisk.partmap
else
rm -f /tmp/sysupgrade.always.overwrite.bootdisk.partmap
fi
run_hooks "" $sysupgrade_pre_upgrade run_hooks "" $sysupgrade_pre_upgrade
# Some platforms/devices may want different sysupgrade process, e.g. without install_bin /sbin/upgraded
# killing processes yet or calling ubus system upgrade method. v "Commencing upgrade. All shell sessions will be closed now."
# This is needed e.g. on NAND devices where we just want to trigger stage1 at ubus call system sysupgrade "{
# this point. \"prefix\": \"$RAM_ROOT\",
if type 'platform_pre_upgrade' >/dev/null 2>/dev/null; then \"path\": $(json_string "$IMAGE"),
platform_pre_upgrade "$ARGV" \"command\": \". /lib/functions.sh; include /lib/upgrade; do_upgrade_stage2\"
fi }"
ubus call system upgrade
touch /tmp/sysupgrade
if [ ! -f /tmp/failsafe ] ; then
kill_remaining TERM
sleep 3
kill_remaining KILL
fi
if [ -n "$(rootfs_type)" ]; then
v "Switching to ramdisk..."
run_ramfs '. /lib/functions.sh; include /lib/upgrade; do_upgrade'
else
do_upgrade
fi