%%information
This page describes using the "dd" command on Linux to create an exact copy of an SD card, storing it in a disk image ("img") file, then restoring from a disk image file. It also describes using the __BalenaEtcher__ program to clone SD cards, and __pishrink__ to shrink the size of disk image files.
%%

[{TableOfContents}]


The Raspberry Pi uses an SD card to contain its [operating system]. Once you've gone to the trouble of getting your Pi to the point where it's ''perfect'', wouldn't it be great to do a backup copy? And be able to restore from that backup? Because there's always the chance that something will go wrong, it's generally good to make backups anyway.

Doing a backup of an SD card isn't just a matter of copying a bunch of files, because the SD card on a Pi is split up into multiple __partitions__, and the copy must duplicate not just the file structure and files, ownership and permissions, but the type and layout of the partitions. Copying an entire drive is called "cloning".

%%information
This page describes how to clone an SD card to an "img" file. If you want to copy (clone) an SD card directly to another SD card (i.e., no backup file) the [BalenaEtcher|https://www.balena.io/etcher/] has a Clone feature that does just that. The upside to this is that cloning card-to-card is easier, faster, and more fool-proof. The downside is that you'll need the ability to mount two SD cards to your desktop computer, and you won't end up with a backup file. Backup files are good!
%%

This page is applicable if your desktop computer uses Linux or Mac OS. If you're using Windows you can do this using the ''Windows Subsystem for Linux'' (WSL), an Ubuntu-as-an-application that can be installed — with some effort — on Windows 10, or using a specialised Windows application. If you want to use Windows, there are many web pages describing how to use Windows applications to copy cards. We don't use Windows around here.


!!! How to Clone an SD Card

! Find Your SD Card

Insert the original SD card into your Linux desktop computer and check the name of the device:
{{{
sudo fdisk -l
}}}
The result will list ''all'' of the drives connected to your computer, which appear in the {{/dev}} directory as if they were files (they're not). You'll need to determine which one of these is your SD card, as you don't want to be messing around with the drives on your desktop. Big mistake.

In my case, I'd inserted a 16GB SD card, so I was looking for a drive around that size (I have no other 16 GB drives so this was sure to be precise). 

At the bottom of the fdisk list I found:
{{{
Disk /dev/sdd: 14.9 GiB, 15931539456 bytes, 31116288 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x06aa76a7

Device     Boot  Start      End  Sectors  Size Id Type
/dev/sdd1         8192   532479   524288  256M  c W95 FAT32 (LBA)
/dev/sdd2       532480 31116287 30583808 14.6G 83 Linux
}}}
This shows a drive of size 14.9GB mounted at the location {{/dev/sdd}}. Note that the usable space on any drive is always less than the advertised size. This drive is split into two partitions, a FAT32 partition of 256MB at {{/dev/sdd1}} and a Linux partition of 14.6GB at {{/dev/sdd2}}. These correspond to the {{/boot}} and {{/}} (main) partitions of our Raspberry Pi OS.

So I've found my SD card at {{/dev/sdd}}. 


! Unmount the SD Card

I need to unmount (disconnect) the drive before making the copy:
{{{
sudo umount /dev/sdd
}}}
If you get a response like "umount: /dev/sdd: not mounted." you'll need to unmount the partitions individually:
{{{
sudo umount /dev/sdd1
sudo umount /dev/sdd2
}}}

!! Making the Backup Copy

%%information
The "{{dd}}" command is part of the Linux OS, you don't need to install any software.
%%

Once you've unmounted the partitions, you can then use the "{{dd}}" command to make the copy. I'll be storing it on my Desktop ("/home/altheim/Desktop") directory as a file named "rpi-backup-20210328.img". I generally add a timestamp to my backups so I can figure out when I made them. If you're using both 32- and 64-bit OS, that's a good thing to add. If the backup is of a particular state of the OS (e.g., before or after a big change) I might include that too.
{{{
sudo dd if=/dev/sdd of=/home/altheim/Desktop/rpi-backup-20210328.img bs=4M status=progress
}}}
%%warning
Note that you __must__ alter the "if" (input file) argument to match the drive of the SD card you found using fdisk, otherwise you may damage an existing drive — particularly when performing a restore (as below). It won't necessarily be the same drive designation as what I found, and an SD card won't even always mount at the same location. ''Check it every time''.
%%
Let's analyse the arguments of that command line:
; "if" : the "input file" and refers to the drive we want to copy
; "of" : the "output file", the "img" file we're going to create. Use a full path to where you want to store the file (I wanted it to show up on my Desktop)
; "bs" : (optional) the size of the blocks of data copied. The default is only 512 bytes, so bumping that up to 4MB will speed up the copying process
; "status" : (optional) shows a helpful progress display during the copying process (e.g., "2357198848 bytes (2.4 GB, 2.2 GiB) copied, 131 s, 18.0 MB/s")

You can type "{{man dd}}" on the command line to see the user manual for "dd".

And then ''be patient'' and don't interrupt things or plug in or disconnect other USB drives while copying. Just let it do its thing. This can take quite awhile for the copying to complete. The bottleneck is the SD card read speed, which for me was around 18MB/second. On a 16GB drive you can do the math. Go get a cup of coffee. Read a book. Take the cat for a walk.

As a point of reference, on my desktop computer (an "Intel® Core™ i5-3570K CPU @ 3.40GHz × 4"), backing up my 16GB SD card using the above command line took 877.819 seconds (almost 15 minutes) to complete. Bumping up the block size from 4MB to 32MB the copy took 887.095 seconds, i.e., it made no noticeable difference.


!! Shrinking the Image

%%information
If you're using Ubuntu Linux as your normal desktop I'd recommend using the __shrink tool__ found at: [https://github.com/qrti/shrink]
which works very well. Instructions for installation can be found at its home page.
__shrink__ automatically opens the GParted Partition Editor, instructs you what to do, and effectively manages the creation and shrinking of the produced copy of your SD card as an *.image file.
%%

There's a bit of a problem in that the Raspberry Pi OS is automatically expanded to the size of the
SD card the first time it's used, meaning that the image is always the same size as the SD card. This means 
that sometimes when you try to write the image to an SD card it is just ''slightly'' too big and you 
end up with an "out of space" error.

The way to fix this is to run a free bash script called "__pishrink__" to shrink the image. This only 
runs on Linux or Mac OS (since it has a BSD Unix command line). 

You can find a copy of PiShrink from its github page at: [https://github.com/Drewsif/PiShrink]

Note that you'll have to make the program executable after downloading it via:
{{{
chmod 744 pishrink.sh
}}}

It has command line help and even has an option for using multiple cores of your computer to speed things 
up, if you've installed the "pigz" library (using {{sudo apt install pigz}}).

!!! How To Restore an SD Card From a Backup

%%information
This describes how to restore an SD card from an "img" file. You can use the Linux "dd" command as described below, or one of the existing UI applications like the [BalenaEtcher|https://www.balena.io/etcher/] or the [Raspberry Pi Imager|https://www.raspberrypi.org/blog/raspberry-pi-imager-imaging-utility/]. The UI applications are friendlier, handle the SD card formatting, and provide error messages and validation, so are __recommended__. The "dd" method is included here for completeness.
%%

! Find Your SD Card (Again)

Using the instructions [above|#section-HowToBackupAnSdCard-FindYourSDCard] with fdisk, locate your SD card.
 
In my case, it turns out that the new card mounted at {{/dev/sdd}}.


! Format Your New SD Card

From a Linux desktop you can use the __Disks__ utility to reformat the entire drive (not simply its partitions), first unmounting and then deleting all partitions, then using "Format Volume" with an Ext4 format. Alternately, you can use __gparted__ (the Gnome Partition Editor), installed via: {{sudo apt install gparted}}. It's a bit beyond the scope here to describe how to reformat the drive using these GUI tools but we'll cover the command line approach because ''it's actually easier'' if you know what you're doing. If not, there's a slight learning curve but I'd probably recommend installing and using gparted. It's a good skill to have anyway.


So we delete any partitions on the SD card (we'll use "/dev/sdd" but you should substitute the mount point you found):
{{{
sudo fdisk /dev/sdd
}}}
This responds with a prompt, where you type "d":
{{{
 Command (m for help): d
 Selected partition 1
 Partition 1 has been deleted.
}}}
If you have multiple partitions on the SD card you can select the partitions or simply repeat the command until the SD card has no more partitions.

Now check to see what your SD card looks like:
{{{
Disk /dev/sdd: 14.6 GiB, 15665725440 bytes, 30597120 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x334dade7
}}}
Now, to create a single FAT32 partition, type "n", selected "p" for primary, then accepted all the defaults:
{{{
Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-30597119, default 2048): 
Last sector, +sectors or +size{K,M,G,T,P} (2048-30597119, default 30597119): 

Created a new partition 1 of type 'Linux' and of size 14.6 GiB.
}}}
Now we'll set the partition type to FAT32. The command is "t", and you can list all the available types with "L". The label for "W95 FAT32" is "b" so we'll respond with "b":
{{{
Hex code (type L to list all codes): b
Changed type of partition 'Linux' to 'W95 FAT32'.
}}}
Now, write the changes you've made to the SD card:
{{{
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
}}}
So, we've created a partition but it's not net formatted. So let's format our new partition using the {{mkfs.vfat}} according to the specifications you've configured:
{{{
sudo mkfs.vfat /dev/sdd1
}}}
You'll note we're using "sdd1" rather than "sdd" because we're formatting the first (and only) ''partition'', not the ''drive'' itself.

! Copy the Raspberry Pi OS Image to the SD Card

Now that you've got a freshly-formatted SD card mounted (we'll assume here at {{/dev/sdd}} but may be different for you), we can restore our image file to that SD card using the {{dd}} command:
{{{
sudo dd if=/home/altheim/Desktop/rpi-backup-20210328.img of=/dev/sdd bs=4M status=progress
}}}
The awake among you will note that this reverses the {{if}} and {{of}} argument values from when we made the backup, since we're just reversing the process.  

And yes, this will take a ''long'' time so take your cat for another walk.

As a point of reference, this process is writing to rather than reading from the SD card, so it's a bit slower at ~16.0MB/second. To restore the Raspberry Pi OS image back to my 16GB SD card took over 1000 seconds (16 minutes).


----

[{Tag OperatingSystem, RaspberryPi}]