This assumes you’ve already used “blkid”, “fdisk -l”, etc. to determine which drive is which. All of these commands require root.
N = (number of partitions * 128) + 1024
The drive in question has 4 partitions, so N=1536
In this example, I’m using an eMMC drive: /dev/mmcblk0
Each partition appends “p<number>” after mmcblk0, such as “/dev/mmcblk0p1”
If you’re using a normal hard drive or USB drive as your source, it will show up as /dev/sd<letter><partition number>
My storage drive is mounted at /mnt/
Because one of the drives involved (storage drive) is connected via USB, it’s important to sync between transfers. I find that using the “sync” mount option slows things down more than syncing manually.
First, backup the partition table:
dd if=/dev/mmcblk0 of=/mnt/mmcblk0.img bs=1 count=1536 && sync
(Note: the output filename is arbitrary.)
Next, back up each partition, syncing between transfers:
dd if=/dev/mmcblk0p1 of=/mnt/mmcblk0p1.img bs=4096 && sync && dd if=/dev/mmcblk0p2 of=/mnt/mmcblk0p2.img bs=4096 && sync && dd if=/dev/mmcblk0p3 of=/mnt/mmcblk0p3.img bs=4096 && sync && dd if=/dev/mmcblk0p4 of=/mnt/mmcblk0p4.img bs=4096 && sync
(Note 1: “bs=4096” sets “block size” to 4KiB, which speeds up the transfer. Default is “bs=512”, which works, but more slowly.)
(Note 2: each “&&” tells the shell to only execute the command that comes next if the previous command worked. This can also be accomplished with scripting, loops, etc.)
When you’re done, you should have a set of files representing the partition table and all the partitions. They will be as big as the source data, so you may want to compress it with gzip or similar. (This can be done with a pipe, but it might introduce a point of failure, so I don’t recommend it.) To restore the data, first restore the partition table:
dd of=/dev/mmcblk0 if=/mnt/mmcblk0.img bs=1 count=1536 && sync && partprobe
(Note: I switched “if” with “of”, and added “&& partprobe” at the end.)
Then, restore each partition with the same command you used to create the backups, but swapping “if” and “of” after each instance of the string, “dd”:
dd of=/dev/mmcblk0p1 if=/mnt/mmcblk0p1.img bs=4096 && sync && dd of=/dev/mmcblk0p2 if=/mnt/mmcblk0p2.img bs=4096 && sync && dd of=/dev/mmcblk0p3 if=/mnt/mmcblk0p3.img bs=4096 && sync && dd of=/dev/mmcblk0p4 if=/mnt/mmcblk0p4.img bs=4096 && sync && partprobe
(Note: the “&& partprobe” at the end may not be totally necessary. You may, however, have to reboot/replug the drives, regardless, at some point, to get the drive geometry to be properly refreshed in the OS.)
If, at any point, you run into errors, try removing “bs=4096” from each command that has it. It will make the transfers slower, but more reliable.
Want to check the progress of a dd operation? You can do this by sending dd the “USR1” signal. If you have only one instance of dd going, you can simply do the following:
killall -USR1 dd
This will cause all dd commands to output–in their own terminals–their current status. If you have multiple dd commands running, and only want to get a progress report from one of them, you can do this:
ps -A | grep dd (Note the number to the left of the "dd" entry.) kill -s USR1 <number>
Finally, if you want to periodically check on a dd command without having to keep typing or hitting ENTER, you can do the following. In this example, “<command>” refers to either “kill -s USR1 <number>” or “killall -USR1 dd”. Note that reporting progress uses more clock cycles than one would think, so it’s best to do so only once every few minutes. This example checks once every 3 minutes.
while `true` ; do <command> ; sleep 180 ; done
(Note that the marks around “true” are backticks, not single quotes. On a typical QWERTY keyboard, these are to the left of the “1” key, on the same button as “~”.)
You can press CTRL-C in the appropriate terminal to stop any of the above commands.