I'm going to assume that your "source" installation is purely on ZFS, and boots directly from the ZFS pool.
Since you're cloning between two different filesystem types, you'll likely want to use a tool like rsync
to accomplish this. You'll mount the source heirarchy (your ZFS pool) at one mountpoint, and mount the destination heirarchy (one or more UFS filesystems) at a different mountpoint. Finally, you will use rsync
to copy the source heirarchy to the destination.
Start by reading the zpool
man page. zpool
has many sub-commands, and each in turn have their own man pages. For starters, note the zpool import
command:
zpool-import(8)
Make disks containing ZFS storage pools available for use on the
system.
and refer to man zpool-import
:
zpool import [-D] [-d dir|device]…
Lists pools available to import.
Note that the the arguments are optional. You'll likely not need them. You're wise to boot from a USB stick to do this work. Once you've booted from your USB stick, zpool import
will show you the pools that are available to you. Begin by just verifying your source ZFS pool, which I'll refer to as tank
in this example.
# zpool import
pool: tank
id: 11588110742206048524
state: ONLINE
action: The pool can be imported using its name or numeric identifier.
config:
tank ONLINE
gpt/zfs-57SCK7S0FVLC ONLINE
gpt/zfs-57SCK7S1FVLC ONLINE
Be careful when mounting "foreign" ZFS pools -- pools that are not directly related to the operation of the system that is mounting them. It's very easy to inadvertently mount a foreign ZFS pool or filesystem right over the top of your running system's filesystem(s), an operation which may not be reversible without rebooting.
Once you've made certain that your source ZFS pool is available to you, you're ready to mount the source (ZFS) and destination (UFS) filesystems and begin.
Mount the source ZFS filesystems
Again from man zpool-import
:
-R root
Sets the cachefile property to none and the altroot
property to root.
zpool import -R /mnt tank
allows you to mount the entire ZFS heirarchy of pool tank
under a different mountpoint, in this case, /mnt
. It's probably a good idea to keep the source pool read-only as well. The commands
# zpool import -o readonly=on -R /mnt tank
# zfs list -r tank
# zfs mount
will mount your source pool in read-only mode under /mnt
and then list the individual ZFS filesystems that are present, and which ones are mounted. You may see a message to the effect of:
cannot import 'tank': pool was previously in use from another system.
Last accessed by <unknown> (hostid=0) at Tue Apr 19 03:29:13 2022
The pool can be imported, use 'zpool import -f' to import the pool.
If this happens, then as it says, simply add the -f
option to your zpool import
command:
# zpool import -f -o readonly=on -R /mnt tank
So that's your source tree.
Mount the destination filesystem(s)
I'll use /mnt.new
as the mountpoint for your destination filesystem, which you say will likely be UFS. Be aware that if you will use a non-ZFS filesystem for the /mnt.new
structure, you will need to run 'newfs' on each disk partition (/dev/ada0p1
, /dev/ada0p2
, etc.) that you will use. As always, be very certain that you know which device is which, and that your get them correct.
Once you've made the filesystems pristine with newfs
, mount the partition that will be your /
filesystem under /mnt.new
and create any directories that will be needed as next-level mountpoints for your UFS heirarchy. Then mount the next-level disk partitions, with each partition mounted on its correct point. For example, if your new UFS filesystem root will be /dev/ada0p1, with /usr
on /dev/ada0p2, and /usr/home
on /dev/ada0p3, then you'll need to:
mkdir /mnt.new
mount /dev/ada0p1 /mnt.new
mkdir /mnt.new/usr
mount /dev/ada0p2 /mnt.new/usr
mkdir /mnt.new/usr/home
mount /dev/ada0p3 /mnt.new/usr/home
Make a mental note that after you're done cloning to the /mnt.new
mountpoint, you likewise will need to edit /mnt.new/etc/fstab
and ensure that it correctly mounts the disk partitions containing your filesystems.
This is basic UFS filesystem management, so I won't go into further detail.
Rsync your source heirarchy to the destination
Once you've got your source ZFS tree mounted at /mnt
and your destination UFS tree mounted under /mnt.new
you can simply copy the files from one to the other. rsync
is a good tool for this.
# rsync -HAXav /mnt/ /mnt.new/
The trailing slashes on /mnt/
are important, and are included on /mnt.new/
"in solidarity." The command as given will list each filename as it is copied. If you prefer not to see that detail, omit the v
from the command.
After you've copied the files across, you will still need to attend to a few manual changes. As mentioned earlier, you will need to inspect /mnt.new/etc/fstab
and make any changes required to ensure that your UFS filesystems get mounted properly when the new system boots. You should also review /mnt.new/etc/rc.conf
to comment out lines like zfs_enable='yes'
as well as similar entries in /mnt.new/boot/loader.conf
.
Unmount the source and destination heirarchies and reboot
When you think the new system is ready to try, export your source ZFS pool:
zpool export tank
and unmount your UFS devices from /mnt.new
:
umount /mnt.new/usr/home
umount /mnt.new/usr
umount /mnt.new
Now you can cross your fingers and reboot to the UFS drive. Keep the USB stick handy so that you can troubleshoot in case your UFS disk doesn't boot on the first try.