Backup (or Clone) a Raspberry Pi SD Card 6


Raspberry Pi Logo All right, you’ve spent countless sleepless nights working on that ultra cool Raspberry Pi project, and now you’re thinking about the unthinkable. What happens if my Raspberry Pi or SD Card dies? Do I have a backup? Can I quickly get up and running? The answer is probably NO.

So being an avid Raspberry Pi hobbyist, I’ve probably already piqued your interest. You also probably already know that the SD Card in your Pi is like a ticking time bomb – waiting to go off at the slightest movement and prompting you to curse loudly in your mother tongue. That cheap SD Card indeed has a set number of writes and not to mention is quite prone to data corruption from various sources. Oh my, what to do…

So now that I’ve scared you silly, I’ll go over some backup options that you yourself can follow to prevent the unthinkable from happening. Some easy, others more technical. In the end, you’ll be equipped with what you need to stave off a night of aggravation and profanity.

I like to separate the backup methods into three possible scenarios:

Type of Backups

  1. Block per block copy
  2. Shrink, then copy
  3. File based copy (live option)

Requirements

If you don’t already have, I highly recommend to purchase a USB SD Card Reader. I have something like this:

USB Card Reader

USB Card Reader

1. Block per block (1-to-1 copy)

Back to it. A block per block copy usually involves using a tool like dd (on Linux / Mac OS X) to perform the backup or dump.

A command like dd copies data from one location to another, overwriting existing data as it goes. Needless to say, this can be dangerous and is most certainly irreversible. Don’t blindly copy the commands below without ensuring they’re applicable to your specific case – adapt them if necessary. Don’t use dd while sleep deprived. You have been warned.

Advantages

  • Relatively simple with the right OS
  • dd is a workhorse and quite robust
  • Availability (installed by default on Linux / Mac OS X, Windows version exists)

Disadvantages

  • Time consuming
  • Resulting file size large (same size as source disk w/o compression)
  • Dangerous if you don’t know what you are doing
  • Can only restore to similar sized SD Cards or bigger

Steps

The first step in using this tool is getting your SD Card in your reader, connecting it to either a Mac or Linux PC and determining the disk identifier you’d like to copy from.

On MAC:

diskutil list

On Linux:

sudo fdisk -l

If you’re on Windows, please refer to Win32DiskImager. However, the rest of this post will assume you’re on a Linux based PC.

Once you know the disk identifier you can begin the backup. The dd command is straight foward. if for input and of for output, bs stand for the block size – I typically use 1m here. pi.img is your image. So assuming your SC Card is rdisk1 or sda, the command is as follows.

On MAC:

sudo dd if=/dev/rdisk1 of=./pi.img bs=1m

On Linux:

sudo dd if=/dev/sda of=./pi.img bs=1m

Restoring the image is just as easy except the if and of parameters are reversed.

On Linux:

sudo dd if=./pi.img of=/dev/sda bs=1m

As noted earlier this produces a file with the same file size as the source SD Card. So if you got a 32GB card, you’ll end up with a close to equal file size which could be quite wasteful, especially if you’re using only 3GB of that card in your running system. You could potentially mitigate this a little with compression by using gzip but don’t expect miracles. Unless you zero-out all that empty space prior to running a backup (and I won’t be going into that here), you’ll probably see little improvement. Again, your mileage will vary here as it relates to file size.

Backup:

sudo dd if=/dev/rdisk1 bs=1m | gzip > ~/Desktop/pi.gz

Restore:

gzip -dc ~/Desktop/pi.gz | sudo dd of=/dev/rdisk1 bs=1m

2. Shrink, then copy

This method involves reducing the size of the main Linux partition on the SD Card and then performing the backup – all done on another PC, preferably one running Linux. A tool like GParted or similar is instrumental here. I employed this technique in the series of blog posts devoted to installing a Triple Boot System on the Pi. I suggest you take a look there.

In short the process is something like this: on a Linux based system attach your SD Card into a reader, shrink the Linux Partition (ext4) to something that just encompasses the data within it. Then perform a backup using dd of the boot (fat32) and linux (ext4) partitions. To restore: plop the new SD Card in, create the partitions, restore and resize the ext4 partition. Again take a look at the following blog post for more info: Triple Boot Raspberry Pi on USB (Raspbian / RetroPie / OpenELEC) – Part 2.

Advantages

  • Resulting file sizes are small
  • Can restore to any size SD Card

Disadvantages

  • Time consuming and more complex
  • Dangerous if you don’t know what you are doing

Steps

Visitor abracadabricx was kind enough to provide a script. Please see the comments section below for his work. Thanks again!

3. File based copy (live option)

A third and final option is using Rsync to perform a file based copy.

rsync is a widely-used utility to keep copies of a file on two computer systems the same. It is commonly found on Unix-like systems and functions as both a file synchronization and file transfer program

The good news here is that your don’t need to understand too much about the rsync command as many scripting geniuses out there have done the dirty work for us. I wholeheartedly suggest using a script called rpi-clone to make your backup. The script is run on a live Raspberry Pi system which sets it apart from the previous two methods I just described. You’ll once again need a USB Card reader, this time directly connected to your Raspberry Pi.

Advantages

  • Easy as Pi (sorry, that was lame…)
  • Can restore directly to an SD Card
  • Can restore to any size SD Card
  • Can provide incremental backups

Disadvantages

  • Runs on a Raspberry Pi live system
  • Problematic when running other disk writing programs or applications

Steps

To install, login to your Raspberry Pi via a terminal. Go to https://github.com/billw2/rpi-clone and download the zip file:

unzip rpi-clone-master.zip
cd rpi-clone-master
cp rpi-clone /usr/local/sbin

or, use git to clone the repository:

git clone https://github.com/billw2/rpi-clone.git 
cd rpi-clone
cp rpi-clone /usr/local/sbin

Next, put your new SD Card into the USB card reader and connect it to the Raspberry Pi. Determine the Linux device of the destination SD card (refer to method 1. for Linux), hint: it’s usually sda. Now issue the command as root and sit back and watch files fly by your terminal in awe…

sudo rpi-clone sda -v -x

Recap

As that unusual and bewildering expression goes, there’s more than one way to skin a cat. And in the same vain, I’m sure there’s many more ways to backup a Raspberry Pi SD Card that I’m neglecting to mention. But as it stands now, for me, method 3 is by far the easiest and quickest.

I do hope it’s given you ample knowledge and courage to perform your very own Raspberry Pi backups. Be well and keep on tech’ing!


Leave a comment

Your email address will not be published. Required fields are marked *

6 thoughts on “Backup (or Clone) a Raspberry Pi SD Card

  • abracadabricx

    Hi, I recognise your story, I have a few of those projects….. To alleviate the two disadvantages of your second approach I wrote a rudimentary bash script. The approach is to take the sd card from the PI and slot it in some linux computer that you use to make a backup. The script measures and calculate a minimum image size, shrinks the filesystem and subsequently the partition on the sd card, which is quite fast. After that it writes an image of only those blocks that are part of the resized partitions to a location of choice. It works well, and all images made have been succesfully tested. You’re welcome to use or share it, and I’ll be happy to learn how it could be improved. Let me know what you think.

    #!/bin/bash -e
    #######!/bin/bash -ex # The x is to be used for debugging.

    #——————————————————————————
    #
    # 9 may 2016, backuPi.sh
    #
    #
    # Calculates the minimum size of the sd card, and then resizes filesystem
    # and partition.
    # Subsequently creates an image of the relevant partitions space.
    #
    #
    #
    #——————————————————————————

    function calcMiB()
    {
    # Calculate size in MiB, for easier reading.
    local partsizeblocks=$1
    local KBperblock=$2
    local partsizeKiB=$(( ${partsizeblocks} * ${KBperblock} ))
    local quotientMiB=”$(( (${partsizeblocks} * ${KBperblock}) / 1024 ))”
    local modulusMiB=$(( ($partsizeKiB – ($quotientMiB * 1024))*1000/1024))
    local modulusMiB2=”$(( (${partsizeblocks} % ${KBperblock}) / 1024))”
    echo “${quotientMiB},${modulusMiB} MiB.”
    }

    # check which drive is the sd card:
    echo “Please select the drive you want to format and write an image to.”
    echo “The following filesystems have been found:”
    lsblk
    read -e -p “Which blockdevice: ” -i “sdc” myblkdev
    read -e -p “Which partition do you want to shrink: ” -i “2” targetpartnr
    targetpart=”${myblkdev}${targetpartnr}”

    # Unmount directories, otherwise online shrinking from resize2fs would be
    # required but this throws an error.
    if grep -s “${myblkdev}” /proc/mounts
    then
    echo “Start unmounting partitions”
    sudo umount -v “/dev/${myblkdev}”? # Questionmark is wildcard.
    fi

    # Check the filesystem/partition.
    sudo e2fsck -fy “/dev/${targetpart}”

    myblockcount=$(sudo tune2fs -l “/dev/${targetpart}” | grep ‘Block count’ | awk ‘{print $3}’)
    myfreeblocks=$(sudo tune2fs -l “/dev/${targetpart}” | grep ‘Free blocks’ | awk ‘{print $3}’)
    myblocksize=$(sudo tune2fs -l “/dev/${targetpart}” | grep ‘Block size’ | awk ‘{print $3}’)
    mysectorsize=$(sudo sfdisk -l “/dev/${myblkdev}” | grep Units | awk ‘{print $8}’)
    mystartsector=$(sudo fdisk -l “/dev/${myblkdev}” | grep “${targetpart}” | awk ‘{print $2}’)

    # Calculate the smallest partition size, in blocks.
    myusedblocks=$(( $myblockcount – $myfreeblocks ))
    # Calculate target partion size, adding a bit of margin, about 8%.
    mytargetblocks=$(( $myusedblocks + ($myusedblocks * 2 / 25) ))

    # Calculate KiB per block to aid further calculation in KiB’s:
    if (( “${myblocksize}” >= “1024” ))
    then
    KBperblock=$(( $myblocksize/1024 ))
    else
    echo “Blocksize is awkward: ${myblocksize}. Not sure what to do, stopping.”
    exit
    fi

    # Round up new part size to multiple of blocksize to facilitate creation.
    mynewpartsize=$(( (($mytargetblocks + $KBperblock-1) / $KBperblock) * $KBperblock ))

    # Calculate and print the existing data and target partition size.
    echo “”
    echo “The size of the data on partion /dev/${targetpart} is \
    $( calcMiB ${myusedblocks} ${KBperblock} )”
    echo “”
    echo “The new size of the data on partion /dev/${targetpart} will be \
    $( calcMiB ${mytargetblocks} ${KBperblock} )”
    echo “”

    # Calculate multiplier from sector size to block size
    sectorsperblock=$(( $myblocksize/$mysectorsize ))
    # Calculate end point in sectors, that is what fdisk requires.
    mynewendpoint=$(( $mystartsector + ($mynewpartsize * $sectorsperblock) ))

    # Start execution:
    # Resize the filesystem, values in 1024 bytes, see the “K” at the end.
    # Example, if blocksize was 4096, nr of blocks x 4 is the resize value.
    sudo resize2fs -fp “/dev/${targetpart}” $(( $mynewpartsize * $KBperblock ))K
    # Resize partion, to make matters complicated values are in sector sizes.
    # NB, the -s switch does not work, putting Yes after the command is the work around.
    sudo parted “/dev/${myblkdev}” unit s resizepart “${targetpartnr}” “${mynewendpoint}” yes
    sync

    # Mounting the drives does not work: error looking up object with path ….
    #udisksctl mount -p block_devices/sdc1
    #udisksctl mount -p block_devices/sdc2
    #udisksctl mount -b /dev/sdc1
    #udisksctl mount -b /dev/sdc2

    # Backup resized image
    read -e -p “Backup the resized image? [Y/N] ” -i “Y” backupchoice

    if [[ “${backupchoice}” =~ ^([yY][eE][sS]|[yY])$ ]]
    then
    mkdir -p ~/backups
    read -e -p “Filename :” -i “$(date +%g%m%d)-raspbianbackup.img” Pibackupname
    sudo dd if=”/dev/${myblkdev}” | pv | sudo dd of=~/backups/”${Pibackupname}” bs=512 count=”${mynewendpoint}”
    echo “Backup succesfull.”
    fi
    exit

    • bobby Post author

      Wow, great work! I have yet to test it, but I’ll be sure to do so soon. Thanks for your contribution, it’s much appreciated.

    • Anton

      Hi abracadabricx,

      Thanks for sharing this. I’m a noob to linux and I’m not quite sure how to use this script. I tried to typing the commands one after other and it didn’t work. Highly appreciated if you can explain how can I use your script. Thanks!

      Cheers,
      Anton

    • Anton

      Hi abracadabricx,

      Can you please explain how can I use your script ? I’m quite new to Linux and Raspberry Pi world. Appreciated if you can advise how can I execute your script. Many Thanks!

    • bobby Post author

      Hi Chuck,
      Thank you for visiting my site. In regards to your question, I really can’t say. It’s not something I tried.
      Sorry.