From 41fd50d20ba31d73c4796c5b2d4eb44ad2258b90 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 20 Dec 2016 01:19:32 +0100 Subject: [PATCH] x86: generalize partition discovery for sysupgrade Backport a few patches to allow sysupgrades on mmcblk and similar block devices. --- ...eserve-partition-table-on-sysupgrade.patch | 135 +++++++++++++ ...6-make-sysupgrade-work-without-partx.patch | 74 +++++++ ...-search-PARTUUID-in-any-block-device.patch | 22 +++ ...e-partition-discovery-for-sysupgrade.patch | 182 ++++++++++++++++++ 4 files changed, 413 insertions(+) create mode 100644 patches/openwrt/0089-x86-preserve-partition-table-on-sysupgrade.patch create mode 100644 patches/openwrt/0090-x86-make-sysupgrade-work-without-partx.patch create mode 100644 patches/openwrt/0091-x86-search-PARTUUID-in-any-block-device.patch create mode 100644 patches/openwrt/0092-x86-generalize-partition-discovery-for-sysupgrade.patch diff --git a/patches/openwrt/0089-x86-preserve-partition-table-on-sysupgrade.patch b/patches/openwrt/0089-x86-preserve-partition-table-on-sysupgrade.patch new file mode 100644 index 00000000..8b50fcaa --- /dev/null +++ b/patches/openwrt/0089-x86-preserve-partition-table-on-sysupgrade.patch @@ -0,0 +1,135 @@ +From: Jo-Philipp Wich +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 + +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() { # [...] + 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 + ++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() { # ++ 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 + } diff --git a/patches/openwrt/0090-x86-make-sysupgrade-work-without-partx.patch b/patches/openwrt/0090-x86-make-sysupgrade-work-without-partx.patch new file mode 100644 index 00000000..852c088d --- /dev/null +++ b/patches/openwrt/0090-x86-make-sysupgrade-work-without-partx.patch @@ -0,0 +1,74 @@ +From: Jo-Philipp Wich +Date: Wed, 30 Mar 2016 03:10:51 +0200 +Subject: x86: make sysupgrade work without partx + +Signed-off-by: Jo-Philipp Wich + +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() { # + + 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..." diff --git a/patches/openwrt/0091-x86-search-PARTUUID-in-any-block-device.patch b/patches/openwrt/0091-x86-search-PARTUUID-in-any-block-device.patch new file mode 100644 index 00000000..19f3652c --- /dev/null +++ b/patches/openwrt/0091-x86-search-PARTUUID-in-any-block-device.patch @@ -0,0 +1,22 @@ +From: Jo-Philipp Wich +Date: Wed, 30 Mar 2016 03:19:23 +0200 +Subject: x86: search PARTUUID in any block device + +Signed-off-by: Jo-Philipp Wich + +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" diff --git a/patches/openwrt/0092-x86-generalize-partition-discovery-for-sysupgrade.patch b/patches/openwrt/0092-x86-generalize-partition-discovery-for-sysupgrade.patch new file mode 100644 index 00000000..3c973aea --- /dev/null +++ b/patches/openwrt/0092-x86-generalize-partition-discovery-for-sysupgrade.patch @@ -0,0 +1,182 @@ +From: Jo-Philipp Wich +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 +Signed-off-by: Jo-Philipp Wich + +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() { # [...] + /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() { # + } + + 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