In a separate thread, I asked about how to change UUIDs on a cloned drive, so that both drives could be used from the same machine:
With lots of help I figured it out, and eventually posted a script that did all the work. Problem: the script was buggy, and I found this out too late to fix it in the thread. So, here’s the no-longer-buggy script:
#!/usr/bin/env bash
#
# For use on a cloned drive. Randomizes the drive and file system UUIDs, while leaving the
# drive bootable.
#
# Assumptions:
# - Recent version of openSUSE
# - Root partition is btrfs
# - sudo is timestamped so one password entry gives you multiple accesses
# - (probably others)
set -o errexit
set -o pipefail
TMPDIR=''
CLEANUP=1
Cleanup() {
if [ -n "$CLEANUP" ]; then
if [ -n "$TMPDIR" ]; then
rm -rf "$TMPDIR"
fi
else
if [ -n "$TMPDIR" ]; then
echo "There is debris which you should clean up here: '$TMPDIR'"
fi
fi
}
Bail() {
if [ -n "$*" ]; then
echo "ERROR: $*"
fi
Cleanup
exit 1
}
Usage() {
echo "Takes three arguments:"
echo " <drive device> (e.g. '/dev/sda')"
echo " <EFI partition number> (e.g. '1')"
echo " <root partition number> (e.g. '2')"
Bail
}
GetFSType() {
sudo lsblk -o FSTYPE "$1" 2>/dev/null | tail -n1
}
GetFSUUID() {
sudo lsblk -o UUID "$1" 2>/dev/null | tail -n1
}
GetDriveUUID() {
sudo fdisk -l "$1" | grep 'Disk identifier: ' | cut -c18-
}
DRIVE="$1"
for PARTITION_SEPARATOR in '' 'p'; do
if [ -b "$1$PARTITION_SEPARATOR$2" ]; then
break
fi
done
EFI_PARTITION="$1$PARTITION_SEPARATOR$2"
ROOT_PARTITION="$1$PARTITION_SEPARATOR$3"
if ! sudo --validate --prompt "[sudo] Need root access, so enter root password: " ; then
Bail "Must have root access"
fi
if [ $# -ne 3 ]; then
Usage
elif [ ! "${DRIVE:0:5}" = "/dev/" ]; then
echo "Bad format for drive device '$DRIVE'"
Usage
elif [ ! -b "$DRIVE" ]; then
echo "Can't access drive device '$DRIVE'"
Usage
elif [ ! -b "$EFI_PARTITION" ]; then
echo "Can't access EFI partition at ''$EFI_PARTITION''"
Usage
elif [ ! "$(GetFSType "$EFI_PARTITION")" = "vfat" ]; then
echo "Bad EFI partition at '$EFI_PARTITION' (expected vfat, found $(GetFSType "$EFI_PARTITION"))"
elif [ ! -b "$ROOT_PARTITION" ]; then
echo "Can't access root partition at '$ROOT_PARTITION'"
Usage
elif [ ! "$(GetFSType "$ROOT_PARTITION")" = "btrfs" ]; then
echo "Bad root partition at '$ROOT_PARTITION' (must be btrfs, found $(GetFSType "$ROOT_PARTITION"))"
elif [ -n "$(findmnt "$ROOT_PARTITION")" ]; then
Bail "Root partition '$ROOT_PARTITION' already mounted; please unmount"
elif [ -n "$(findmnt "$EFI_PARTITION")" ]; then
Bail "EFI partition '$EFI_PARTITION' already mounted; please unmount"
fi
echo
################ Get old UUIDs ################
echo "Old drive '$DRIVE' UUID is '$(GetDriveUUID "$DRIVE")'"
ROOT_OLD_UUID="$(GetFSUUID "$ROOT_PARTITION")"
echo "Old root partition '$ROOT_PARTITION' file system UUID is '$ROOT_OLD_UUID'"
if [ ! "${#ROOT_OLD_UUID}" -eq 36 ]; then
Bail "unexpected UUID length (${#ROOT_OLD_UUID}) of partition '$ROOT_PARTITION'"
fi
################ Update drive UUID ################
echo "Randomizing drive UUID"
echo "x
f
w
y" | sudo gdisk "$DRIVE" >/dev/null
if [ "$?" -ne 0 ]; then
echo "Blew it"
Bail
fi
echo "New drive '$DRIVE' UUID is '$(GetDriveUUID "$DRIVE")'"
echo
################ Update root partition file system UUID ################
echo "Randomizing root partition UUID..."
if sudo btrfstune -u -f "$ROOT_PARTITION"; then
echo "... done."
else
echo "... FAILED!!!!! BAILING!!!!!"
Bail
fi
ROOT_NEW_UUID="$(GetFSUUID "$ROOT_PARTITION")"
echo "Root partition '$ROOT_PARTITION' file system UUID is now '$ROOT_NEW_UUID'"
################ Mount all necessary partitions ################
TMPDIR="$(mktemp -d)"
echo "Mounting partitions on $TMPDIR"
if ! sudo mount "$ROOT_PARTITION" "$TMPDIR"; then
Bail "mount $ROOT_PARTITION $TMPDIR failed"
fi
if ! sudo mount "$EFI_PARTITION" "$TMPDIR/boot/efi"; then
Bail "mount $EFI_PARTITION $TMPDIR/boot/efi failed"
fi
# Only needed to chroot grub2-editenv dummy
for dir in /dev /proc /sys /run; do
if ! sudo mount --bind "$dir" "$TMPDIR$dir"; then
Bail "mount $dir $TMPDIR$dir failed"
fi
done
################ Fix fstab and grub.cfg files ################
echo "Fix fstab"
sudo sed --in-place='.bak' "s/$ROOT_OLD_UUID/$ROOT_NEW_UUID/g" "$TMPDIR/etc/fstab"
# The grub.cfg files are very clearly marked "DO NOT EDIT". But, the following is the
# best way to fix them, given that we aren't changing anything else except for the
# root partition UUID.
echo "Fix /boot/efi/EFI/opensuse/grub.cfg"
sudo sed --in-place='.bak' "s/$ROOT_OLD_UUID/$ROOT_NEW_UUID/g" "$TMPDIR/boot/efi/EFI/opensuse/grub.cfg"
echo "Fix /boot/grub2/grub.cfg"
sudo sed --in-place='.bak' "s/$ROOT_OLD_UUID/$ROOT_NEW_UUID/g" "$TMPDIR/boot/grub2/grub.cfg"
# Editing /boot/grub2/grub.cfg breaks the grubenv file; rebuild
echo "Rebuild grub environment block"
if ! sudo chroot "$TMPDIR" grub2-editenv - unset dummy; then
Bail "'sudo chroot $TMPDIR grub2-editenv - unset dummy' failed!"
fi
################ Unmount everything ################
# Can't really handle errors here, so don't try.
for dir in /dev /proc /sys /run; do
sudo umount "$TMPDIR$dir"
done
sudo umount "$TMPDIR/boot/efi"
sudo umount "$TMPDIR"
Cleanup
echo "Done."
Thanks for all who helped!