Browse Source

x86: generalize partition discovery for sysupgrade

Backport a few patches to allow sysupgrades on mmcblk and similar block
devices.
Matthias Schiffer 7 years ago
parent
commit
1f08074438

+ 135 - 0
patches/openwrt/0086-x86-preserve-partition-table-on-sysupgrade.patch

@@ -0,0 +1,135 @@
+From: Jo-Philipp Wich <jow@openwrt.org>
+Date: Tue, 9 Feb 2016 12:33:17 +0000
+Subject: x86: preserve partition table on sysupgrade
+
+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>
+
+Backport of OpenWrt r48682
+
+diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh
+index 761b4c17957e2cf63b88025520b6fba59c890255..dc865544f65c16399dcced55b8b09c671b31b5d1 100644
+--- a/package/base-files/files/lib/upgrade/common.sh
++++ b/package/base-files/files/lib/upgrade/common.sh
+@@ -67,6 +67,7 @@ run_ramfs() { # <command> [...]
+ 	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
+diff --git a/package/base-files/files/sbin/sysupgrade b/package/base-files/files/sbin/sysupgrade
+index ef83c4b00f1a88ae5d68fc70adf51a6af3dc109c..759c841e131a415c8009995c372cce1f55fb78a0 100755
+--- a/package/base-files/files/sbin/sysupgrade
++++ b/package/base-files/files/sbin/sysupgrade
+@@ -10,6 +10,7 @@ export INTERACTIVE=0
+ 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
+@@ -29,6 +30,7 @@ while [ -n "$1" ]; do
+ 		-q) export VERBOSE="$(($VERBOSE - 1))";;
+ 		-n) export SAVE_CONFIG=0;;
+ 		-c) export SAVE_OVERLAY=1;;
++		-p) export SAVE_PARTITIONS=0;;
+ 		-b|--create-backup) export CONF_BACKUP="$2" NEED_IMAGE=1; shift;;
+ 		-r|--restore-backup) export CONF_RESTORE="$2" NEED_IMAGE=1; shift;;
+ 		-l|--list-backup) export CONF_BACKUP_LIST=1; break;;
+@@ -62,6 +64,7 @@ upgrade-option:
+ 	-i           interactive mode
+ 	-c           attempt to preserve all changed files in /etc/
+ 	-n           do not save configuration over reflash
++	-p           do not attempt to restore the partition table after flash.
+ 	-T | --test
+ 	             Verify image and config .tar.gz but do not actually flash.
+ 	-F | --force
+diff --git a/target/linux/x86/Makefile b/target/linux/x86/Makefile
+index ba733c02480b248aa95331da2bcd8fee3e25f812..29a232296a02b253344927a61eecb40503473d59 100644
+--- a/target/linux/x86/Makefile
++++ b/target/linux/x86/Makefile
+@@ -13,6 +13,8 @@ FEATURES:=squashfs ext4 vdi vmdk pcmcia targz
+ SUBTARGETS=generic xen_domu ep80579 geode kvm_guest rdc 64
+ MAINTAINER:=Felix Fietkau <nbd@openwrt.org>
+ 
++DEFAULT_PACKAGES += partx-utils
++
+ KERNEL_PATCHVER:=3.18
+ 
+ KERNELNAME:=bzImage
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index adc119c897ed840aef17c2041a48244d0922564e..c21f1a7e5feba553110f138c14977daaa472da70 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -55,12 +55,59 @@ platform_copy_config() {
+ 	fi
+ }
+ 
++get_partitions() { # <device> <filename>
++	local disk="$1"
++	local filename="$2"
++
++	if [ -b "$disk" -o -f "$disk" ]; then
++		echo "Reading partition table from $filename..."
++		partx -r "$disk" -gbo NR,START,SECTORS > "/tmp/partx.$filename"
++	fi
++}
++
+ platform_do_upgrade() {
+ 	platform_export_bootpart
++	disk="${BOOTPART%[0-9]}"
+ 
+-	if [ -b "${BOOTPART%[0-9]}" ]; then
++	if [ -b "$disk" ]; then
+ 		sync
+-		get_image "$@" | dd of="${BOOTPART%[0-9]}" bs=4096 conv=fsync
++		if [ "$SAVE_PARTITIONS" = "1" ]; then
++			get_partitions "$disk" bootdisk
++
++
++			#get block size
++			sectors="$(partx -r $disk -gbo SECTORS --nr 1:1)"
++			size="$(partx -r $disk -gbo SIZE --nr 1:1)"
++			ibs="$(($size / $sectors))"
++
++			#extract the boot sector from the image
++			get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
++
++			get_partitions /tmp/image.bs image
++
++			#compare tables
++			diff="$(grep -F -x -v -f /tmp/partx.bootdisk /tmp/partx.image)"
++			if [ -n "$diff" ]; then
++				echo "Partition layout is changed.  Full image will be written."
++				ask_bool 0 "Abort" && exit
++
++				get_image "$@" | dd of="$disk" bs=4096 conv=fsync
++				return 0
++			fi
++
++			#iterate over each partition from the image and write it to the boot disk
++			while read part start size; do
++			echo "Writing image to $disk$part..."
++				get_image "$@" | dd of="$disk$part" ibs="$ibs" obs=1M skip="$start" count="$size" conv=fsync
++			done < /tmp/partx.image
++
++			#copy partition uuid
++			echo "Writing new UUID to $disk$part..."
++			get_image "$@" | dd of="$disk" bs=1 skip=440 count=4 seek=440 conv=fsync
++		else
++			get_image "$@" | dd of="$disk" bs=4096 conv=fsync
++		fi
++
+ 		sleep 1
+ 	fi
+ }

+ 74 - 0
patches/openwrt/0087-x86-make-sysupgrade-work-without-partx.patch

@@ -0,0 +1,74 @@
+From: Jo-Philipp Wich <jo@mein.io>
+Date: Wed, 30 Mar 2016 03:10:51 +0200
+Subject: x86: make sysupgrade work without partx
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+Backport of LEDE 9f422eba7c1a297a96a03b1cce05fa3cb9d71a4a
+
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index c21f1a7e5feba553110f138c14977daaa472da70..f12deebf6484df6f3f69e453ad67688a76d57972 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -61,7 +61,27 @@ get_partitions() { # <device> <filename>
+ 
+ 	if [ -b "$disk" -o -f "$disk" ]; then
+ 		echo "Reading partition table from $filename..."
+-		partx -r "$disk" -gbo NR,START,SECTORS > "/tmp/partx.$filename"
++
++		local magic="$(hexdump -v -n 2 -s 0x1FE -e '1/2 "0x%04X"' "$disk")"
++		if [ "$magic" != 0xAA55 ]; then
++			echo "Invalid partition table on $disk"
++			exit
++		fi
++
++		rm -f "/tmp/partmap.$filename"
++
++		local part
++		for part in 1 2 3 4; do
++			set -- $(hexdump -v -n 12 -s "$((0x1B2 + $part * 16))" -e '3/4 "0x%08X "' "$disk")
++
++			local type="$(($1 % 256))"
++			local lba="$(($2))"
++			local num="$(($3))"
++
++			[ $type -gt 0 ] || continue
++
++			printf "%2d %5d %7d\n" $part $lba $num >> "/tmp/partmap.$filename"
++		done
+ 	fi
+ }
+ 
+@@ -76,9 +96,11 @@ platform_do_upgrade() {
+ 
+ 
+ 			#get block size
+-			sectors="$(partx -r $disk -gbo SECTORS --nr 1:1)"
+-			size="$(partx -r $disk -gbo SIZE --nr 1:1)"
+-			ibs="$(($size / $sectors))"
++			if [ -f "/sys/block/${disk##*/}/queue/physical_block_size" ]; then
++				ibs="$(cat "/sys/block/${disk##*/}/queue/physical_block_size")"
++			else
++				ibs=512
++			fi
+ 
+ 			#extract the boot sector from the image
+ 			get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
+@@ -86,7 +108,7 @@ platform_do_upgrade() {
+ 			get_partitions /tmp/image.bs image
+ 
+ 			#compare tables
+-			diff="$(grep -F -x -v -f /tmp/partx.bootdisk /tmp/partx.image)"
++			diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
+ 			if [ -n "$diff" ]; then
+ 				echo "Partition layout is changed.  Full image will be written."
+ 				ask_bool 0 "Abort" && exit
+@@ -99,7 +121,7 @@ platform_do_upgrade() {
+ 			while read part start size; do
+ 			echo "Writing image to $disk$part..."
+ 				get_image "$@" | dd of="$disk$part" ibs="$ibs" obs=1M skip="$start" count="$size" conv=fsync
+-			done < /tmp/partx.image
++			done < /tmp/partmap.image
+ 
+ 			#copy partition uuid
+ 			echo "Writing new UUID to $disk$part..."

+ 22 - 0
patches/openwrt/0088-x86-search-PARTUUID-in-any-block-device.patch

@@ -0,0 +1,22 @@
+From: Jo-Philipp Wich <jo@mein.io>
+Date: Wed, 30 Mar 2016 03:19:23 +0200
+Subject: x86: search PARTUUID in any block device
+
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+Backport of LEDE 924fb794bde41eca8289c6cf10322bf6683b4a80
+
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index f12deebf6484df6f3f69e453ad67688a76d57972..29eac77dfb0ae52f241696f3f62dce7d16106b20 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -17,7 +17,8 @@ platform_export_bootpart() {
+ 			PARTUUID=[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]-02)
+ 				uuid="${disk#PARTUUID=}"
+ 				uuid="${uuid%-02}"
+-				for disk in /dev/[hsv]d[a-z] /dev/xvd[a-z]; do
++				for disk in /dev/*; do
++					[ -b "$disk" ] || continue
+ 					set -- $(dd if=$disk bs=1 skip=440 count=4 2>/dev/null | hexdump -v -e '4/1 "%02x "')
+ 					if [ "$4$3$2$1" = "$uuid" ]; then
+ 						export BOOTPART="${disk}1"

+ 182 - 0
patches/openwrt/0089-x86-generalize-partition-discovery-for-sysupgrade.patch

@@ -0,0 +1,182 @@
+From: Jo-Philipp Wich <jo@mein.io>
+Date: Tue, 24 May 2016 12:07:02 +0200
+Subject: x86: generalize partition discovery for sysupgrade
+
+Generalize the partition discovery in sysupgrade in order to fix sysupgrade
+and config backup/recovery on MMC block devices which use a different naming
+scheme compared to mtdblock or sd* devices.
+
+The change also adds the find applet to the ramdisk utilities so that upgrade
+code can rely on it.
+
+The commit is based on the initial submission by Russell Senior at
+http://patchwork.ozlabs.org/patch/625440/ .
+
+Signed-off-by: Russell Senior <russell@personaltelco.net>
+Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+
+Backport of LEDE 1012701014bd944197031a3c0023527861b521b4
+
+diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh
+index dc865544f65c16399dcced55b8b09c671b31b5d1..14684959dd46d04b1c4b72213dbe06943ae64686 100644
+--- a/package/base-files/files/lib/upgrade/common.sh
++++ b/package/base-files/files/lib/upgrade/common.sh
+@@ -53,7 +53,7 @@ run_ramfs() { # <command> [...]
+ 		/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
++		/bin/rm /usr/bin/basename /bin/kill /bin/chmod /usr/bin/find
+ 
+ 	install_bin /sbin/mtd
+ 	install_bin /sbin/mount_root
+diff --git a/target/linux/x86/base-files/lib/preinit/79_move_config b/target/linux/x86/base-files/lib/preinit/79_move_config
+index 1d4873d78b480cb3f11e04e6246559417b431a8a..5ac81cb90d1c15782a9c4f271720cfa66d6d03a9 100644
+--- a/target/linux/x86/base-files/lib/preinit/79_move_config
++++ b/target/linux/x86/base-files/lib/preinit/79_move_config
+@@ -2,10 +2,12 @@
+ # Copyright (C) 2012-2015 OpenWrt.org
+ 
+ move_config() {
++	local partdev
++
+ 	. /lib/upgrade/platform.sh
+ 
+-	if platform_export_bootpart; then
+-		mount -t ext4 -o rw,noatime "$BOOTPART" /mnt
++	if platform_export_bootdevice && platform_export_partdevice partdev 1; then
++		mount -t ext4 -o rw,noatime "/dev/$partdev" /mnt
+ 		mv -f /mnt/sysupgrade.tgz /
+ 		umount /mnt
+ 	fi
+diff --git a/target/linux/x86/base-files/lib/upgrade/platform.sh b/target/linux/x86/base-files/lib/upgrade/platform.sh
+index 29eac77dfb0ae52f241696f3f62dce7d16106b20..c8bc3f7f608fc82ee3afc049b64af3a740fd2c37 100644
+--- a/target/linux/x86/base-files/lib/upgrade/platform.sh
++++ b/target/linux/x86/base-files/lib/upgrade/platform.sh
+@@ -1,5 +1,21 @@
+-platform_export_bootpart() {
+-	local cmdline uuid disk
++platform_export_partdevice() {
++	local var="$1" offset="$2"
++	local uevent MAJOR MINOR DEVNAME DEVTYPE
++
++	for uevent in /sys/class/block/*/uevent; do
++		. "$uevent"
++		if [ $BOOTDEV_MAJOR = $MAJOR -a $(($BOOTDEV_MINOR + $offset)) = $MINOR -a -b "/dev/$DEVNAME" ]; then
++			export "$var=$DEVNAME"
++			return 0
++		fi
++	done
++
++	return 1
++}
++
++platform_export_bootdevice() {
++	local cmdline uuid disk uevent
++	local MAJOR MINOR DEVNAME DEVTYPE
+ 
+ 	if read cmdline < /proc/cmdline; then
+ 		case "$cmdline" in
+@@ -17,20 +33,27 @@ platform_export_bootpart() {
+ 			PARTUUID=[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]-02)
+ 				uuid="${disk#PARTUUID=}"
+ 				uuid="${uuid%-02}"
+-				for disk in /dev/*; do
+-					[ -b "$disk" ] || continue
++				for disk in $(find /dev -type b); do
+ 					set -- $(dd if=$disk bs=1 skip=440 count=4 2>/dev/null | hexdump -v -e '4/1 "%02x "')
+ 					if [ "$4$3$2$1" = "$uuid" ]; then
+-						export BOOTPART="${disk}1"
+-						return 0
++						uevent="/sys/class/block/${disk##*/}/uevent"
++						break
+ 					fi
+ 				done
+ 			;;
+ 			/dev/*)
+-				export BOOTPART="${disk%[0-9]}1"
+-				return 0
++				uevent="/sys/class/block/${disk##*/}/uevent"
+ 			;;
+ 		esac
++
++		if [ -e "$uevent" ]; then
++			. "$uevent"
++
++			export BOOTDEV_MAJOR=$MAJOR
++			export BOOTDEV_MINOR=$MINOR
++
++			return 0
++		fi
+ 	fi
+ 
+ 	return 1
+@@ -49,8 +72,10 @@ platform_check_image() {
+ }
+ 
+ platform_copy_config() {
+-	if [ -b "$BOOTPART" ]; then
+-		mount -t ext4 -o rw,noatime "$BOOTPART" /mnt
++	local partdev
++
++	if platform_export_partdevice partdev 1; then
++		mount -t ext4 -o rw,noatime "/dev/$partdev" /mnt
+ 		cp -af "$CONF_TAR" /mnt/
+ 		umount /mnt
+ 	fi
+@@ -87,18 +112,16 @@ get_partitions() { # <device> <filename>
+ }
+ 
+ platform_do_upgrade() {
+-	platform_export_bootpart
+-	disk="${BOOTPART%[0-9]}"
++	local diskdev partdev ibs diff
+ 
+-	if [ -b "$disk" ]; then
++	if platform_export_bootdevice && platform_export_partdevice diskdev 0; then
+ 		sync
+ 		if [ "$SAVE_PARTITIONS" = "1" ]; then
+-			get_partitions "$disk" bootdisk
+-
++			get_partitions "/dev/$diskdev" bootdisk
+ 
+ 			#get block size
+-			if [ -f "/sys/block/${disk##*/}/queue/physical_block_size" ]; then
+-				ibs="$(cat "/sys/block/${disk##*/}/queue/physical_block_size")"
++			if [ -f "/sys/block/$diskdev/queue/physical_block_size" ]; then
++				ibs="$(cat "/sys/block/$diskdev/queue/physical_block_size")"
+ 			else
+ 				ibs=512
+ 			fi
+@@ -114,21 +137,25 @@ platform_do_upgrade() {
+ 				echo "Partition layout is changed.  Full image will be written."
+ 				ask_bool 0 "Abort" && exit
+ 
+-				get_image "$@" | dd of="$disk" bs=4096 conv=fsync
++				get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+ 				return 0
+ 			fi
+ 
+ 			#iterate over each partition from the image and write it to the boot disk
+ 			while read part start size; do
+-			echo "Writing image to $disk$part..."
+-				get_image "$@" | dd of="$disk$part" ibs="$ibs" obs=1M skip="$start" count="$size" conv=fsync
++				if platform_export_partdevice partdev $part; then
++					echo "Writing image to /dev/$partdev..."
++					get_image "$@" | dd of="/dev/$partdev" ibs="$ibs" obs=1M skip="$start" count="$size" conv=fsync
++				else
++					echo "Unable to find partition $part device, skipped."
++				fi
+ 			done < /tmp/partmap.image
+ 
+ 			#copy partition uuid
+-			echo "Writing new UUID to $disk$part..."
+-			get_image "$@" | dd of="$disk" bs=1 skip=440 count=4 seek=440 conv=fsync
++			echo "Writing new UUID to /dev/$diskdev..."
++			get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
+ 		else
+-			get_image "$@" | dd of="$disk" bs=4096 conv=fsync
++			get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
+ 		fi
+ 
+ 		sleep 1