From 06abdd47ffb8df68e48b182c6650752fa24eaed9 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 13 Jul 2020 21:40:10 +0200 Subject: [PATCH 1/5] Use lsblk to show all FS labels Previously, e2label was used, but that only works for ext partitions. Using lsblk allows showing the filesystem labels for all filesystems supported by the kernel. --- rpi-clone | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/rpi-clone b/rpi-clone index b6baf53..5f2c397 100755 --- a/rpi-clone +++ b/rpi-clone @@ -739,13 +739,10 @@ do src_name[p]="${src_mounted_dir[p]}" fi - if [[ "$part_type" == *"ext"* ]] + label=`lsblk --raw --output label --noheadings "${src_device[p]}"` + if [ "$label" != "" ] then - label=`e2label ${src_device[p]} 2> /dev/null` - if [ "$label" != "" ] - then - src_label[p]="$label" - fi + src_label[p]="$label" fi done @@ -1139,16 +1136,15 @@ do if [[ "$part_type" == *"linux-swap"* ]] then dst_fs_type[p]="swap" - elif [[ "$part_type" == *"ext"* ]] + elif ((p == ext_num)) then - label=`e2label ${dst_device[p]} 2> /dev/null` + dst_fs_type[p]="EXT" + else + label=`lsblk --raw --output label --noheadings "${dst_device[p]}"` if [ "$label" != "" ] then dst_label[p]="$label" fi - elif ((p == ext_num)) - then - dst_fs_type[p]="EXT" fi done From 74eb6a75721e0f52e166d7de314fd71421989a62 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 14 Jul 2020 14:26:42 +0200 Subject: [PATCH 2/5] Use previously retrieved destination root FS label Now labels are retrieved for all destination partitions, there is no longer any point in separately retrieving the destination root label, just use the previously retrieved label. --- rpi-clone | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/rpi-clone b/rpi-clone index 5f2c397..4ff5380 100755 --- a/rpi-clone +++ b/rpi-clone @@ -1766,12 +1766,7 @@ fi rm -f $clone/etc/udev/rules.d/70-persistent-net.rules -dst_root_vol_name=`e2label $dst_root_dev` - -if [ "$dst_root_vol_name" = "" ] -then - dst_root_vol_name="no label" -fi +dst_root_vol_name=${dst_label[$root_part_num]} if ((have_grub)) then From 3441dace223580ca45d5877de0b8ccb952873747 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 13 Jul 2020 21:44:46 +0200 Subject: [PATCH 3/5] Preserve existing FS labels where possible Instead of only setting FS labels on ext partitions when specified with the --label-partitions option and leave all other partitions unlabeled, this tries to copy the source filesystem labels to the destination where possible. Setting labels requires filesystem-specific commands or mkfs options, so not all filesystems are supported. For changing labels on existing partitions, only ext and fat partitions are supported. For mkfs a few more are supported, though these are probably not used in practice. This also refactors some of the code, introducing a `mkfs_label()` and `change_label()` function to prevent having to duplicate the filesystem-type checking code. This fixes #100. --- rpi-clone | 109 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 38 deletions(-) diff --git a/rpi-clone b/rpi-clone index 4ff5380..611f7bd 100755 --- a/rpi-clone +++ b/rpi-clone @@ -546,26 +546,80 @@ print_options() printf "%-23s:\n" "-----------------------" } -ext_label() +dst_part_label() { pnum=$1 fs_type=$2 - flag=$3 - label_arg="" + label="" if [ "$ext_label" != "" ] && [[ "$fs_type" == *"ext"* ]] then rep="${ext_label: -1}" if [ "$rep" == "#" ] then - label_arg=${ext_label:: -1} - label_arg="$flag $label_arg$pnum" + label="${ext_label:: -1}" elif ((pnum == root_part_num)) then - label_arg="$flag $ext_label" + label="$ext_label" fi fi - printf -v "${4}" "%s" "$label_arg" + + if [ -z "$label" -a -n "${src_label[$pnum]}" ] + then + label="${src_label[$pnum]}" + fi + printf -v "${3}" "%s" "$label" + } + +mkfs_label() + { + pnum=$1 + fs_type=$2 + + label_flag="" + case "$fs_type" in + # This list is probably overcomplete, but might simplify + # future additions. + vfat|msdos|exfat|fat16|fat32) + label_flag=-n + ;; + ext2|ext3|ext4|ntfs|xfs) + label_flag=-L + ;; + hfs|hfsplus) + label_flag=-v + ;; + reiserfs) + label_flag=-l + ;; + esac + + + label_arg="" + dst_part_label "$pnum" "$fs_type" label + if [ -n "$label" -a -n "$label_flag" ] + then + label_arg="$label_flag $label" + fi + printf -v "${3}" "%s" "$label_arg" + } + +change_label() + { + pnum=$1 + fs_type=$2 + dev=$3 + + dst_part_label "$pnum" "$fs_type" label + if [ "$label" != "" ] && [[ "$fs_type" == *"ext"* ]] + then + echo " e2label $dev $label" + e2label $dev $label + elif [ "$label" != "" ] && [[ "$fs_type" == *"fat"* ]] + then + echo " fatlabel $dev $label" + fatlabel $dev $label + fi } get_src_disk() @@ -1501,9 +1555,9 @@ Use -U for unattended even if initializing. if [ "${src_mounted_dir[p]}" == "/boot" ] && ((p == 1)) then - ext_label $p "$fs_type" "-L" label - printf " => mkfs -t $mkfs_type $label $dst_dev ..." - yes | mkfs -t $mkfs_type $label $dst_dev &>> /tmp/$PGM-output + mkfs_label $p "$fs_type" label_opt + printf " => mkfs -t $fs_type $label_opt $dst_dev ..." + yes | mkfs -t $mkfs_type $label_opt $dst_dev &>> /tmp/$PGM-output echo "" else if [ "$fs_type" == "swap" ] @@ -1514,9 +1568,9 @@ Use -U for unattended even if initializing. then if [ "${src_mounted_dir[p]}" != "" ] || ((p == n_image_parts)) then - ext_label $p $fs_type "-L" label - printf " => mkfs -t $mkfs_type $label $dst_dev ..." - yes | mkfs -t $mkfs_type $label $dst_dev &>> /tmp/$PGM-output + mkfs_label "$p" "$fs_type" label_opt + printf " => mkfs -t $mkfs_type $label_opt $dst_dev ..." + yes | mkfs -t $mkfs_type $label_opt $dst_dev &>> /tmp/$PGM-output echo "" if ((p == n_image_parts)) then @@ -1536,12 +1590,7 @@ Use -U for unattended even if initializing. else echo "" fi - ext_label $p $fs_type "" label - if [ "$label" != "" ] - then - echo " e2label $dst_dev $label" - e2label $dst_dev $label - fi + change_label "$p" "$fs_type" "$dst_dev" fi fi fi @@ -1663,13 +1712,7 @@ do sync_msg_done=1 dst_dev=/dev/${dst_part_base}${p} fs_type=${src_fs_type[$p]} - ext_label $p $fs_type "" label - if [ "$label" != "" ] - then - qecho " e2label $dst_dev $label" - e2label $dst_dev $label - fi - + change_label "$p" "$fs_type" "$dst_dev" mount_partition ${src_device[p]} $clone_src "" mount_partition $dst_dev $clone "$clone_src" unmount_list="$clone_src $clone" @@ -1681,12 +1724,7 @@ done qprintf "Syncing mounted partitions:\n" fs_type=${src_fs_type[$root_part_num]} -ext_label $root_part_num $fs_type "" label -if [ "$label" != "" ] -then - qecho " e2label $dst_root_dev $label" - e2label $dst_root_dev $label -fi +change_label "$root_part_num" "$fs_type" "$dst_root_dev" mount_partition $dst_root_dev $clone "" unmount_list="$clone" @@ -1709,12 +1747,7 @@ do dst_dev=/dev/${dst_part_base}${p} fs_type=${src_fs_type[$p]} - ext_label $p $fs_type "" label - if [ "$label" != "" ] - then - qecho " e2label $dst_dev $label" - e2label $dst_dev $label - fi + change_label "$p" "$fs_type" "$dst_dev" mount_partition "$dst_dev" "$dst_dir" "$unmount_list" rsync_file_system "${src_mounted_dir[p]}/" "${dst_dir}" "" From 2f062a9589958b0ababca97aaa67808426e36cc3 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 15 Mar 2022 14:54:52 +0100 Subject: [PATCH 4/5] Run parted with --script This makes it non-interactive and prevents the script from silently hanging when parted finds something weird, e.g.: $ sudo rpi-clone /dev/sda Warning: The driver descriptor says the physical block size is 2048 bytes, but Linux says it is 512 bytes. This just hangs, because parted is waiting for an answer: $ sudo parted -m /dev/sda unit s print Warning: The driver descriptor says the physical block size is 2048 bytes, but Linux says it is 512 bytes. Ignore/Cancel? --- rpi-clone | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpi-clone b/rpi-clone index 611f7bd..32abda5 100755 --- a/rpi-clone +++ b/rpi-clone @@ -690,7 +690,7 @@ fi # src_root_dev, if on device other than booted, is not in src_partition_table # and src_fdisk_table, but is in src_df_table and src_mount_table # -src_partition_table=$(parted -m "/dev/$src_disk" unit s print | tr -d ';') +src_partition_table=$(parted --script -m "/dev/$src_disk" unit s print | tr -d ';') src_fdisk_table=$(fdisk -l /dev/$src_disk | grep "^/dev/") tmp=$(df | grep -e "^/dev/$src_disk" -e "^/dev/root" -e "$src_root_dev" \ @@ -1137,7 +1137,7 @@ then exit 1 fi -dst_partition_table=$(parted -m "/dev/$dst_disk" unit s print | tr -d ';') +dst_partition_table=$(parted --script -m "/dev/$dst_disk" unit s print | tr -d ';') n_dst_parts=$(echo "$dst_partition_table" | tail -n 1 | cut -d ":" -f 1) if [ "$n_dst_parts" == "/dev/$dst_disk" ] then From 0ca374dcd8fd873678d831af671032387f9e53ea Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Tue, 15 Mar 2022 16:59:19 +0100 Subject: [PATCH 5/5] Run udevadm settle after running parted It seems that parted can force a partition scan (observed on a removable USB disk), which temporaly clears the filesystem labels from lsblk output. To prevent this, call udevadm settle to wait until all udev events are processed before continuing. --- rpi-clone | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rpi-clone b/rpi-clone index 32abda5..cbf8e24 100755 --- a/rpi-clone +++ b/rpi-clone @@ -692,6 +692,9 @@ fi # src_partition_table=$(parted --script -m "/dev/$src_disk" unit s print | tr -d ';') src_fdisk_table=$(fdisk -l /dev/$src_disk | grep "^/dev/") +# Parted seems to force a partition rescan, which hides fs labels from +# lsblk output. Wait for kernel/udev to be done processing. +udevadm settle tmp=$(df | grep -e "^/dev/$src_disk" -e "^/dev/root" -e "$src_root_dev" \ | tr -s " ") @@ -1138,6 +1141,10 @@ then fi dst_partition_table=$(parted --script -m "/dev/$dst_disk" unit s print | tr -d ';') +# Parted seems to force a partition rescan, which hides fs labels from +# lsblk output. Wait for kernel/udev to be done processing. +udevadm settle + n_dst_parts=$(echo "$dst_partition_table" | tail -n 1 | cut -d ":" -f 1) if [ "$n_dst_parts" == "/dev/$dst_disk" ] then