Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support UUID= (filesystem UUIDs), Armbian and partially Ubuntu #140

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

matthijskooijman
Copy link

This makes two changes:

  1. Supporting systems (such as Armbian) that use UUID= (filesystem uuids) rather than PARTUUID= (partition uuids)
  2. Suppporting Armbian by editing /boot/armbianEnv.txt instead of /boot/cmdline.txt if the former exists but the latter does not.

With these changes, I was able to run rpi-clone on an Orange Pi PC running Armbian (but I expect it to run on most if not all other Armbian-supported boards as well). I tried both a stock image with a single partition, as well as a self-compiled image with 2 partitions (/boot and /). I also tried imaging SD to USB with -l, which then boots from USB succesfully, and then swapping out the SD card and image back from USB to SD (without -l), which produces a working SD again.

One thing I did not implement is changing the FS UUID for partitions that are copied using dd, so for these partitions you might end up with duplicate UUIDS. I'm not exactly sure when this happens (I think only for partitions that are not mounted, so maybe the duplicate UUIDs are not problematic directly), but this might need a better looking at.

Note that this PR includes the commits of #101, since I needed both so I developed this on top of that and because they touch nearby code, there's merge conflicts when trying to untangle them (which is possible, but would only result in more conflicts when trying to merge both, so I thought it better to just leave them entangled). Effectively this means only the last three commits should be reviewed here, the first 5 are subject of #101.

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.
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.
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 billw2#100.
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?
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.
This supports systems where the filesystem's UUID is specified in fstab
and on the kernel commandline.

This is the first step in supporting Armbian, which uses UUID rather
than PARTUUID.
@matthijskooijman matthijskooijman changed the title Support UUID= (filesystem UUIDs) and Armbian Support UUID= (filesystem UUIDs), Armbian and partially Ubuntu Apr 22, 2022
@matthijskooijman
Copy link
Author

I just pushed one more commit that enables modifying /boot/firmware/cmdline.txt, which where the cmdline is stored in Ubuntu installations. If you modify an Ubuntu installation to use (PART)UUID instead of filesystem labels, this should allow cloning the installation.

@ioogithub, Could you test this?

@ioogithub
Copy link

To confirm, can I test this PR with the following:

git clone https://github.com/matthijskooijman/rpi-clone.git
cd rpi-clone
git checkout support-fsuuid-and-armbian
sudo ./rpi-clone device

@matthijskooijman
Copy link
Author

Yup, that sounds like the correct approach.

@ioogithub
Copy link

I have tested the code, at first it appeared that it had worked because I got this result at the end of the clone:

Editing /boot/firmware/cmdline.txt PARTUUID to use abcdef12
Editing /mnt/clone/etc/fstab PARTUUID to use abcdef12
===============================
Done with clone to /dev/sdb

however when I inspected /mnt/clone/boot/firmware/cmdine.txt I saw this that the PARTUUID was the same on the destination sd card as the original. So even though it said reported that it edited the file it did not or perhaps it did change it but another part of the code changed it back?

I ran the test again with the modified code (above) and I confirmed that it did work.

Im not sure why this change did not work, from looking at your code it looks like it should and it even reported that it made the change so perhaps there is something else that overwrites it back afterwards?

@matthijskooijman
Copy link
Author

however when I inspected /mnt/clone/boot/firmware/cmdine.txt I saw this that the PARTUUID was the same on the destination sd card as the original.

Hm, weird. Did you check that the actual PARTUUIDs were different (or alternatively, that the PARTUUID show in the log output really did not match cmdline.txt)?

I ran the test again with the modified code (above) and I confirmed that it did work.

You mean you ran the test a second time without changing anything? Or is your "above" referring to the other issue where you posted a manual change of the cmdline.txt file?

@ioogithub
Copy link

Hm, weird. Did you check that the actual PARTUUIDs were different (or alternatively, that the PARTUUID show in the log output really did not match cmdline.txt)?
I checked /boot/firmware/cmdline.txt immediately after the operation and noticed that it had the PARTUUID from the source card.

I did notice another unusual event, several hours later I noticed that after a restart I was booted from the /dev/sdb which was was completely unexpected. Is it possible that the code changed the cmdline.txt on the source card and not the destination?

I will do another test, before the test I will check both fstab and cmdline.txt then I will check then again after and report back.

@matthijskooijman
Copy link
Author

Is it possible that the code changed the cmdline.txt on the source card and not the destination?

Yup, that is exactly what happened, thanks for catching that. Turns out the UUID version prepends ${clone} as expected, but the PARTUUID version does not. I thought I had tested this change on Raspbian as well, but maybe I just didn't notice that it booted from the wrong card or something.

I'll push a correction later, maybe tomorrow.

@diagonali
Copy link

Is it possible that the code changed the cmdline.txt on the source card and not the destination?

Yup, that is exactly what happened, thanks for catching that. Turns out the UUID version prepends ${clone} as expected, but the PARTUUID version does not. I thought I had tested this change on Raspbian as well, but maybe I just didn't notice that it booted from the wrong card or something.

I'll push a correction later, maybe tomorrow.

I've spent a lot of time wrestling with trying to get this super useful script which used to work easily with Raspberry Pi OS to use instead with Ubuntu 22.04 on a Raspberry Pi 4 (nothing I tried would get it to boot after cloning with the original script), I finally found your branch and all is now working as expected.

I can clone from sda to mmcblk0 and vice versa and its super useful to be able to keep an SD card in the Pi at all times with a working, bootable copy of the system so that in the event the SSD is unusable or unbootable, I can simply remove the SSD and the Pi will boot from SD where I can then clone back to USB and carry on as before. Thanks so much for your efforts, they're certainly appreciated here! I do hope this script can continue to be improved and I'm also surprised there aren't more similar scripts out there as it's functionality is so useful.

@matthijskooijman
Copy link
Author

Yup, that is exactly what happened, thanks for catching that. Turns out the UUID version prepends ${clone} as expected, but the PARTUUID version does not. I thought I had tested this change on Raspbian as well, but maybe I just didn't notice that it booted from the wrong card or something.

I've just pushed a fixup commit to fix this issue. I haven't tested it, @ioogithub maybe you can check if it works for you now?

@diagonali, good to hear this branch has been useful for you. I'm assuming you have change fstab and cmdline.txt from labels to (PART)UUIDs manually before applying this branch? Also, did you run into the issue from #140 (comment)? Or did you maybe use UUID instead of PARTUUID (UUID already worked, PARTUUID was broken until just now).

@diagonali
Copy link

@matthijskooijman To be honest, despite tinkering with linux for a quite a while now, I haven't fully understood fstab, UUIDs etc and how they relate to use in this script so I didn't do any manual changes at all. Best I tried was specify a label using the original script to try to get the cloned drive to boot in Ubuntu but it didn't work. I'll definitely need to learn about these technicalities eventually though!

I simply installed a fresh Ubuntu 22.04 onto a Raspberry Pi 4 using USB boot and ran your branch of this script to clone to an SD card. Then I removed the USB drive and rebooted and the system boots successfully. Then I plugged in the USB drive and cloned back to that and removed the SD card and again it boots successfully. As far as I can tell there is some new messaging (relating to labels I think?) during runtime which I assume is due to your edits. Also I noticed that running the script with -f flag doesn't seem to do the same thing(s) as running without this flag in terms of making the cloned drive bootable? I didn't get the same issue as the #140 comment as far as I can see.

I've just pushed a fixup commit to fix this issue. I haven't tested it, @ioogithub maybe you can check if it works for you now?

I'm using the following commands to use your branch - use this again to update?:

git clone https://github.com/matthijskooijman/rpi-clone.git
cd rpi-clone
git checkout support-fsuuid-and-armbian
sudo ./rpi-clone device

@matthijskooijman
Copy link
Author

I simply installed a fresh Ubuntu 22.04 onto a Raspberry Pi 4 using USB boot and ran your branch of this script to clone to an SD card. Then I removed the USB drive and rebooted and the system boots successfully.

Ah, you're only keeping either the USB drive or SD card plugged in, that should work even without manual fstab changes indeed (if you plug in both, it might be that you're booting one, but end up with the root filesystem on the other because the labels are identical). This also means that you do not really need this PR (updating UUIDs in cmdline.txt), but #101 is sufficient (but that is included in this PR). if you would convert fstab and cmdline.txt to UUIDs because you want to be able to have both plugged in at the same time, then you would need this PR.

I'm using the following commands to use your branch - use this again to update?:

You could probably also get away with a simple git pull in the existing clone (because I did not do a force push), but using a fresh clone as you suggest will also work fine (you might need to delete the existing clone first).

@diagonali
Copy link

if you would convert fstab and cmdline.txt to UUIDs because you want to be able to have both plugged in at the same time, then you would need this PR.

@matthijskooijman Interesting, I definitely want to be able to keep the SD card inserted when using USB boot (and vice versa) as the SD card operates in my case as a "live" bootable failsafe "backup" in case of issues with the USB drive/installation. It makes sense from what you say that it could boot one but use the filesystem of the other - not ideal obviously!

Question for me now is how to as you say "convert fstab and cmdline.txt to UUIDs". I'll start looking into (Googling) how to do this in Ubuntu on the Raspberry Pi and I'm sure there are guides online. I'm wondering if you could give any simple instructions if this is a simple process? I'll be doing this on a live system so want to make sure I do this correctly. I use my Raspberry Pi as a home automation server so the setup I have needs to be as robust as possible and I avoid the boot/filesystem overlap you mention.

Also I'm wondering if this process could be incorporated into the script itself? Is switching over to using UUIDs too tricky to process in an automated way?

@matthijskooijman
Copy link
Author

@diagonali See the discussion starting at #100 (comment)

Also I'm wondering if this process could be incorporated into the script itself? Is switching over to using UUIDs too tricky to process in an automated way?

It could probably be done (there is already an option and code to switch from device names (e.g. sda1) to PARTUUID), but I won't be doing this (This PR has already gotten more extra changes beyond what I need myself).

@diagonali
Copy link

@diagonali See the discussion starting at #100 (comment)

Also I'm wondering if this process could be incorporated into the script itself? Is switching over to using UUIDs too tricky to process in an automated way?

It could probably be done (there is already an option and code to switch from device names (e.g. sda1) to PARTUUID), but I won't be doing this (This PR has already gotten more extra changes beyond what I need myself).

Ah ok no problem, thanks very much for what you've done so far.

This removes all hardcoded references to cmdline.txt and cmdline.boot by
removing the `$clone` prefix from cmdline_txt and introducing a
cmdline_txt variable.

In addition, this adds some quoting to any lines modified to be a bit
more robust when spaces are involved.

This should not change behavior (apart from maybe in cases with spaces
that were previously broken), the commands ran should be identical.
On Armbian, the kernel commandline (or at least the root device to use)
is stored in armbianEnv.txt rather than cmdline.txt, so update that if
it exists and cmdline.txt does not.

The actual operation on this file is just replacing UUIDs inside the
file, so it works even though the syntax of the file is different.
On Ubuntu, cmdline.txt is stored in a subdirectory, so if the file does
not exist in the usual location, fall back to the Ubuntu location (and
fall back to the Armbian version if the Ubuntu version does not exist
either).

Note that this does not support Ubuntu completely out of the box, since
it uses filesystem labels instead of UUIDs for mounting, but if you
manualy change them to UUIDs, this change allows cloning to work.
This mostly moves code into functions, but also makes minor changes to
how the code is called to prepare for more reuse of this code.

Moving these functions up in the file with the other functions is left
for the next commit to make review easier.

Diff best viewed with --ignore-all-space.
This puts them together with the other function. This commit only moves
code, without making any changes.
This applied largely the same operations to cmdline.txt as
fixup_device_references_in_file did to fstab, so this can just call the
latter.

This should work the same, except that the PARTUUID is not replaced with
the g flag (all occurences instead of just one), all filesystem UUIDs
are replaced (instead of just the root partition), and progress output
messages are slightly different.

Also, fstab UUID= replacements are now done anywhere in the file,
instead of just at the start of a line.
This modifies fixup_device_references_in_file to accept the mountpoint
and filename separately to prevent printing the destination mountpoint
(which might be ugly and meaningless). fixup_boot_partition already had
this.

Then, a partition label is passed which is prefixed to this plain
filename to tell the user which partition is being modified. This could
just have used src_mount, but passing a separate label prepares for
using this code for non-mounted partitions too.

Finally, the UUID output is slightly reworded and some indentation is
added (preparing for this output to also be intermixed with mounting and
rsync calls later).
This facilitates the case where some of the non-mounted partitions
contain a second operating system (possibly for a different
system/board), and updates these so that system also stays working.
Since this is called for fstab on unmounted partitions now, without
checking if the file exists, just silently do nothing if the file does
not exist.
This adds some consistency with fixup_boot_partition, making code easier
to read, and removes duplication of the list of files to update
(currently only fstab).
@matthijskooijman
Copy link
Author

matthijskooijman commented Jul 28, 2022

I did a bit more work on this PR to make rpi-clone update UUIDs in non-mounted partitions as well (plus some refactoring leading up to that). I needed this to work with a dual-boot image/SD-card I have been working with (single image that contains boot+root for both a raspberry pi and an orange pi), but it might be useful for other cases as well.

I did a force push to squash the fixup commit I previously pushed.

Edit: And one more commit to fix permission warnings on FAT filesystems mounted with the uid option, which is really unrelated but I just wanted to publish it somewhere without adding yet another PR

@fjpdevries
Copy link

fjpdevries commented Jul 28, 2022 via email

This can potentially cause rsync error messages, especially if the
filesystem is already mounted with a uid= option (which will not be
copied to the destination mount, leading to different owners and thus
rsync trying and failing to fix the owner).
@KcrPL
Copy link

KcrPL commented Feb 9, 2023

I know it's been some time since someone commented on this but I'd really like to thank you. It took me a lot of time this evening and your fork was a solution to this. Thank you :)

@timo12357
Copy link

I have an Orangepi 3LTS running Armbian 23.8.1 Bullseye with Linux 5.15.93-sunxi64. sys-clone works perfect as long as I have the system on a SD card. I moved the system to the EMMC. The initial sync works, but sys-clone fails to do a subsequent sync complaining that it can not mount the clone disk:

`sudo sys-clone sdc

Destination disk partition /dev/sdc1 is mounted on /mnt/clone.
The clone cannot proceed unless it is unmounted.
Do you want to unmount /mnt/clone? (yes/no): yes

Booted disk: mmcblk2 7,8GB Destination disk: sdc 31,3GB

Part Size FS Label Part Size FS Label
1 root 7 2G ext4 -- 1 29 1G ext4 --

== SYNC mmcblk2 file systems to sdc ==
/ (2,9G used) : SYNC to sdc1 (29,1G size)

Run setup script : no.

Verbose mode : no.

Ok to proceed with the clone? (yes/no): yes

Syncing file systems (can take a long time)
Syncing mounted partitions:
e2label /dev/sdc1 --
Mounting /dev/sdc1 on /mnt/clone
mount: /mnt/clone: wrong fs type, bad option, bad superblock on /dev/sdc1, missing codepage or helper program, or other error.
Mount failure of /dev/sdc1 on /mnt/clone.
Aborting!`

I have tested this with two separate SD cards, and same error occurs. Is this a bug or user error?

@matthijskooijman
Copy link
Author

Hm, so it fails to mount /dev/sdc1 saying the FS is invalid (my interpretation), but it was mountd when you started. Maybe the script messed up the filesystem trying to copy something? Can you manually mount /dev/sdc1 before and after running the script?

Btw, I think this might be unrelated to this particular pullrequest - Yes, you're using Armbian, but the changes in this PR are mostly about updating filesystem references for Armbian, and your problem seems to occur way earlier before even starting to copy files. So maybe it would be better to open up a separate issue for this? Maybe comment with a link to that issue here?

@timo12357
Copy link

This still does not work after updating to Armbian 23.8.3. Anyone else seeing this behavior, or is this a problem with my setup?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants