Skip to content
Snippets Groups Projects
0015-base-files-always-use-staged-sysupgrade.patch 12.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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
    
    Matthias Schiffer's avatar
    Matthias Schiffer committed
    index 8c1b3b180e1ecfdd2c106dd3b8853cd487ff89b4..ef9aac709fc1619ba15eeb0aeb4a9a6a372369b2 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() {
    
    Matthias Schiffer's avatar
    Matthias Schiffer committed
    @@ -331,12 +319,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
    
    Matthias Schiffer's avatar
    Matthias Schiffer committed
    @@ -344,12 +334,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
    
    Matthias Schiffer's avatar
    Matthias Schiffer committed
    index 71c7faa6dbc485ff33e776ff087e1aca58cfb0b0..fa08f4194daa0ee74758b9f49a23fe8dcb4b933d 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.
    
    Matthias Schiffer's avatar
    Matthias Schiffer committed
    @@ -155,14 +155,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
    
    Matthias Schiffer's avatar
    Matthias Schiffer committed
    @@ -203,8 +202,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
    
    Matthias Schiffer's avatar
    Matthias Schiffer committed
    @@ -230,6 +254,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
     
    
    Matthias Schiffer's avatar
    Matthias Schiffer committed
    @@ -237,28 +262,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\"
    +}"