Export the unique, monotonic DISKSEQ sequence drive number instead of its major/minor numbers to identify the boot disk and directly match the partition in export_partdevice with PARTN. The MINOR blockdevice numbers are not guaranteed sequential across disks, it can happen that disks enumerate before their partitions are probed, resulting in interleaved MINOR numbers breaking the partition offset calculation: major minor #blocks name 259 0 250059096 nvme0n1 259 2 8192 nvme0n1p1 259 3 491520 nvme0n1p2 259 4 239 nvme0n1p128 259 1 250059096 nvme1n1 259 5 250057728 nvme1n1p1 Signed-off-by: Clemens Hopfer <openwrt@wireloss.net> Link: https://github.com/openwrt/openwrt/pull/18962 Signed-off-by: Robert Marko <robimarko@gmail.com>
181 lines
4.6 KiB
Bash
181 lines
4.6 KiB
Bash
REQUIRE_IMAGE_METADATA=1
|
|
|
|
UBOOT_ENV_PART=3
|
|
BOOT_PART=4
|
|
ROOTFS_PART=5
|
|
|
|
RAMFS_COPY_BIN='blockdev'
|
|
|
|
export_bootdevice() {
|
|
local cmdline uuid blockdev uevent line class
|
|
local MAJOR MINOR DEVNAME DEVTYPE
|
|
local rootpart="$(cmdline_get_var root)"
|
|
|
|
case "$rootpart" in
|
|
PARTUUID=????????-????-????-????-??????????0?/PARTNROFF=1 | \
|
|
PARTUUID=????????-????-????-????-??????????05)
|
|
uuid="${rootpart#PARTUUID=}"
|
|
uuid="${uuid%/PARTNROFF=1}"
|
|
uuid="${uuid%0?}00"
|
|
for disk in $(find /dev -type b); do
|
|
set -- $(dd if=$disk bs=1 skip=568 count=16 2>/dev/null | hexdump -v -e '8/1 "%02x "" "2/1 "%02x""-"6/1 "%02x"')
|
|
if [ "$4$3$2$1-$6$5-$8$7-$9" = "$uuid" ]; then
|
|
uevent="/sys/class/block/${disk##*/}/uevent"
|
|
break
|
|
fi
|
|
done
|
|
;;
|
|
esac
|
|
|
|
if [ -e "$uevent" ]; then
|
|
while read line; do
|
|
export -n "$line"
|
|
done < "$uevent"
|
|
export BOOTDEV_DISKSEQ=$DISKSEQ
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
platform_check_image() {
|
|
local diskdev partdev diff
|
|
|
|
[ "$#" -gt 1 ] && return 1
|
|
|
|
export_bootdevice && export_partdevice diskdev 0 || {
|
|
v "platform_check_image: Unable to determine upgrade device"
|
|
return 1
|
|
}
|
|
|
|
get_partitions "/dev/$diskdev" bootdisk
|
|
|
|
v "Extract the boot sector from the image"
|
|
get_image_dd "$1" of=/tmp/image.bs count=63 bs=512b
|
|
|
|
get_partitions /tmp/image.bs image
|
|
|
|
#compare tables
|
|
diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
|
|
|
|
rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image
|
|
|
|
if [ -n "$diff" ]; then
|
|
echo "Partition layout has changed. Full image will be written."
|
|
ask_bool 0 "Abort" && exit 1
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
platform_do_upgrade() {
|
|
local diskdev partdev diff partlabel
|
|
|
|
export_bootdevice && export_partdevice diskdev 0 || {
|
|
v "platform_do_upgrade: Unable to determine upgrade device"
|
|
return 1
|
|
}
|
|
|
|
sync
|
|
|
|
if [ "$UPGRADE_OPT_SAVE_PARTITIONS" = "1" ]; then
|
|
get_partitions "/dev/$diskdev" bootdisk
|
|
|
|
v "Extract boot sector from the image"
|
|
get_image_dd "$1" of=/tmp/image.bs count=63 bs=512b
|
|
|
|
get_partitions /tmp/image.bs image
|
|
|
|
#compare tables
|
|
diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
|
|
else
|
|
diff=1
|
|
fi
|
|
|
|
if [ -n "$diff" ]; then
|
|
rm -rf /tmp/ubootenv
|
|
|
|
if export_partdevice partdev $UBOOT_ENV_PART; then
|
|
v "Saving u-boot env (/dev/$partdev) before to write image"
|
|
get_image_dd "/dev/$partdev" of=/tmp/ubootenv
|
|
fi
|
|
|
|
v "Writing image to /dev/$diskdev..."
|
|
get_image_dd "$1" of="/dev/$diskdev" conv=fsync
|
|
|
|
blockdev --rereadpt "/dev/$diskdev"
|
|
|
|
[ -f /tmp/ubootenv ] && {
|
|
# iterate over each partition from the image to find the
|
|
# u-boot-env partition and restore u-boot env.
|
|
while read part start size; do
|
|
if export_partdevice partdev $part; then
|
|
while read line; do
|
|
eval "local l$line"
|
|
done < "/sys/class/block/$partdev/uevent"
|
|
|
|
[ "$lPARTNAME" = "u-boot-env" ] || continue
|
|
|
|
v "Writting u-boot env to /dev/$partdev"
|
|
get_image_dd /tmp/ubootenv of="/dev/$partdev" conv=fsync
|
|
|
|
return 0
|
|
fi
|
|
done < /tmp/partmap.image
|
|
}
|
|
return 0
|
|
fi
|
|
|
|
#iterate over each partition from the image and write it to the boot disk
|
|
while read part start size; do
|
|
if export_partdevice partdev $part; then
|
|
# do not erase u-boot env
|
|
[ "$part" = "$UBOOT_ENV_PART" ] && continue
|
|
|
|
v "Writing image to /dev/$partdev..."
|
|
v "Normal partition, doing DD"
|
|
get_image_dd "$1" of="/dev/$partdev" ibs=512 obs=1M skip="$start" \
|
|
count="$size" conv=fsync
|
|
else
|
|
v "Unable to find partition $part device, skipped."
|
|
fi
|
|
done < /tmp/partmap.image
|
|
|
|
if export_partdevice partdev "$BOOT_PART"; then
|
|
mount -t ext4 -o rw,noatime "/dev/$partdev" /mnt
|
|
local partuuid="$(cmdline_get_var root)"
|
|
v "Setting rootfs ${partuuid}"
|
|
sed -i "s/PARTUUID=[a-f0-9-]\+/${partuuid}/ig" \
|
|
/mnt/extlinux/extlinux.conf
|
|
umount /mnt
|
|
fi
|
|
}
|
|
|
|
platform_copy_config() {
|
|
local partdev
|
|
|
|
# Iterate over each partition from the image to find the boot partition
|
|
# and copy the config tarball.
|
|
# The partlabel is used to find the partition.
|
|
# An hardcoded partition number cannot be used, as it could be wrong if
|
|
# the partition table changed, and the full image was written.
|
|
while read part start size; do
|
|
# config is copied in the boot partition, as for squashfs image, the
|
|
# rootfs partition is not writable.
|
|
if export_partdevice partdev "$part"; then
|
|
while read line; do
|
|
eval "local l$line"
|
|
done < "/sys/class/block/$partdev/uevent"
|
|
|
|
[ "$lPARTNAME" = "boot" ] || continue
|
|
|
|
mount -t ext4 -o rw,noatime "/dev/$partdev" /mnt
|
|
cp -af "$UPGRADE_BACKUP" "/mnt/$BACKUP_FILE"
|
|
umount /mnt
|
|
return 0
|
|
else
|
|
v "ERROR: Unable to find partition to copy config data to"
|
|
fi
|
|
done < /tmp/partmap.image
|
|
}
|
|
|