Backing up and restoring a bootable USB Stick

I recently needed to create a backup of a bootable USB stick. My usual approach is to simply use dd (disk dump) on a Linux system to create a full copy of the stick into an image file. This time I wanted to play around a bit and see if I could store only the relevant data, to restore the stick without storing empty sectors or – even worse – remnants of old, potentially sensitive data from previous uses.

The USB stick in this case was a 8 GByte Sandisk Cruzer Blade with a bootable FAT32 partition on it:

# fdisk -l /dev/sda
Disk /dev/sda: 7.45 GiB, 8004304896 bytes, 15633408 sectors
Disk model: Cruzer Blade    
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: 0x01234567

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1  *     2048 15632383 15630336  7.5G  c W95 FAT32 (LBA)

Step 1: Backing up the Partition Layout

I started with creating a backup of the partition layout. sfdisk comes handy here as it is easily scriptable (not required in this case). You can pipe its output into a text file and use the same file to re-create the partition layout.

# sfdisk -d /dev/sda 
label: dos
label-id: 0x01234567
device: /dev/sda
unit: sectors
sector-size: 512

/dev/sda1 : start=        2048, size=    15630336, type=c, bootable


# sfdisk -d /dev/sda > partition-layout-sda.sfdisk

Step 2: Copying the Boot Sector and Hidden Data

You probably won’t need this step if your USB stick is not bootable. In my case it was a recovery stick so it contained a bootable MBR FAT32 partition. Backing up the boot sector is easy: create a disk dump of the first sector (512 bytes). This sector contains the master boot record (the first 446 bytes), partition table entry points (64 bytes), and two magic bytes (0x55, 0xAA) at the end.

# dd if=/dev/sda of=bootsect-sda.img bs=512 count=1
1+0 records in
1+0 records out
512 bytes copied, 0.00350891 s, 146 kB/s

The Master Boot Record only consists of the first 446 bytes. I’ve taken a shortcut here and stored the whole first sector. When restoring the MBR I will only restore the first 446 bytes of it.

Some disk images can contain additional (secret) data in the gap between the boot sector and the first sector of the first partition. The GRUB2 boot loader for example stores additional data in this area. I haven’t created a backup of these sectors in my test; but if you would need to, the command would look something like this…
(In my case the first partition starts at sector 2048, so there could be about 1 MByte of additional hidden data.)

# dd if=/dev/sda of=bootsect-and-additional-sectors.img bs=512 count=2048
2048+0 records in
2048+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.0616555 s, 17.0 MB/s

Step 3: Creating a backup of the files on the stick

So now we’re getting to the interesting part: creating a copy of the files on the USB stick. And only of the files. A really handy tool for this is partclone. It supports various partition formats and only stores the files without the ‘free’ space.

This can be slightly improved by adding a layer of compression. In my case most of the contents was already compressed, so this step wasn’t a big improvement (only 0.1 GBytes or about 4%):

# partclone.fat32 -c -s /dev/sda1 | gzip -c -9 > sda1.img.gz
Partclone v0.3.13 http://partclone.org
Starting to clone device (/dev/sda1) to image (-)
Reading Super Block
Calculating bitmap... Please wait... 
Elapsed: 00:00:01, Remaining: 00:00:00, Completed: 100.00%                      
Total Time: 00:00:01, 100.00% completed!
done!
File system:  FAT32
Device size:    8,0 GB = 15630336 Blocks
Space in use:   4,6 GB = 8976976 Blocks
Free Space:     3,4 GB = 6653360 Blocks
Block size:   512 Byte
Elapsed: 00:06:10, Remaining: 00:00:00, Completed: 100.00%, Rate: 745,33MB/min, 
current block:   15630336, total block:   15630336, Complete: 100.00%           
Total Time: 00:06:10, Ave. Rate:  745,3MB/min, 100.00% completed!
Syncing... OK!
Partclone successfully cloned the device (/dev/sda1) to the image (-)
Cloned successfully.

Schrödinger’s Backup, or: Restoring the USB Stick

Well, it’s always nice to have a backup; but you need to verify that it can be restored.

The condition of any backup is unknown until a restore is attempted.

Schrödinger’s Backup

My approach was to take another USB stick, erase its contents, and then try to restore the files and images I had created earlier. I probably could have combined these steps into a shell script, but as this was a one-off I simply typed them in.

The first step is to erase the old partition layout – if there is one as in my case.

# fdisk -l /dev/sda
Disk /dev/sda: 7.45 GiB, 8004304896 bytes, 15633408 sectors
Disk model: Cruzer Blade    
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: 0xfedcba98

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1        2048 15632383 15630336  7.5G  b W95 FAT32


# dd if=/dev/zero of=/dev/sda bs=1M count=1; sync
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.114768 s, 9.1 MB/s

Next I’ve recreated the partition layout by piping the ‘partition-layout-sda’ file back into sfdisk.

# sfdisk /dev/sda < partition-layout-sda.sfdisk 
Checking that no-one is using this disk right now ... OK

Disk /dev/sda: 7.45 GiB, 8004304896 bytes, 15633408 sectors
Disk model: Cruzer Blade    
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

>>> Script header accepted.
>>> Script header accepted.
>>> Script header accepted.
>>> Script header accepted.
>>> Script header accepted.
>>> Created a new DOS disklabel with disk identifier 0x01234567.
/dev/sda1: Created a new partition 1 of type 'W95 FAT32 (LBA)' and of size 7.5 GiB.
Partition #1 contains a vfat signature.
/dev/sda2: Done.

New situation:
Disklabel type: dos
Disk identifier: 0x01234567

Device     Boot Start      End  Sectors  Size Id Type
/dev/sda1  *     2048 15632383 15630336  7.5G  c W95 FAT32 (LBA)

The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

After that I recreated the MBR (the first 446 bytes of the boot sector).

# dd if=bootsect-sda.img of=/dev/sda bs=446 count=1
1+0 records in
1+0 records out
446 bytes copied, 0.00312617 s, 143 kB/s

The last step was to restore the files with partclone.

# gzip -c -d sda1.img.gz | partclone.fat32 -r -o /dev/sda1 
Partclone v0.3.13 http://partclone.org
Starting to restore image (-) to device (/dev/sda1)
Calculating bitmap... Please wait...
done!
File system:  FAT32
Device size:    8.0 GB = 15630336 Blocks
Space in use:   4.6 GB = 8976976 Blocks
Free Space:     3.4 GB = 6653360 Blocks
Block size:   512 Byte
Elapsed: 00:03:20, Remaining: 00:00:00, Completed: 100.00%, Rate:   1.38GB/min, 
current block:   15630336, total block:   15630336, Complete: 100.00%           
Total Time: 00:03:20, Ave. Rate:    1.4GB/min, 100.00% completed!
Syncing... OK!
Partclone successfully restored the image (-) to the device (/dev/sda1)
Cloned successfully.

It’s alive

The new stick is bootable. Checksum comparisons during boot did not report any errors. And I was able to significantly reduce the stored data. (I probably would have saved even more on larger USB sticks.)

So in the end, was it worth the time to go through all these steps? Maybe. It definitely was fun to do.

I will continue to simply create disk dumps via dd. But it is good to know that you can reduce the size of such a bootable USB stick if you, for example, need to distribute personalized images to customers and ‘every byte counts’. For everyday use cases I would recommend Clonezilla though. It not only covers all the steps from above, but is also far better field-tested and adapted to various different disk and partition layouts.

Leave a Reply

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