Raspberry Pi SD Card Image is too big for another SD Card
Recently I am working on project involving Raspberry Pi. A couple of months ago I wrote a quick start guide to Raspberry Pi. Now I have another topic to cover that is related to Raspberry and project I am working on. As you know Raspberry Pi does not have hard drive. Instead is used SD card - it loads operating system on SD card, it boots from SD card, it saves data to SD card, etc. And when you work with SD cards from different producers you realize that although cards are equal in size they actually differ with some small bytes. For example I have AData SD card which is 8G but it is slightly bigger that 8G Toshiba SD card. And when I try to save image produced on AData on Toshiba SD card I got error saying that there is not enough space on disk.
When I needs to read/write an image from/to SD card on Windows I use Win32 Disk Imager. It is very simply and nice to have tool. Here is the error which I got from Disk Imager. Here are two screenshots - first one showing file that I selected and prepared for writing and second one is error which it gives back.
Pay attention to highlighted numbers in second screenshot those are available sectors. Actual image has 15130624 sectors, and SD card where we are going to save it has 15126528 sectors. If you pay closer attention to error message you will see that sector size is 512 bytes. So let’s calculate difference
With other words this is 2M difference between those 8G SD cards - one of them AData and second one Tohisba. Ant this 2Mb stops you from writing image to another SD card. Of course there is a solution which includes resizing the image under Linux.
First step is to copy that image into Linux. Then you simply run fdisk -l name of image
Do not pay attention to heads. track, etc. Those are not valid for SD cards. But pay
attention for total sectors - 15130624 and to size of image - 7746 MB. Note that this
image is expanded. But sometimes I got some unexpanded images. You know when you first
boot into Raspbian first thing that is executed is sudo raspi-config. And from this menu
you can expand files system to use entire space on SD card. When you download and get 4G
image for example and save in over 8G card you have 4G free. They are not used until you
do not run sudo raspi-config
. Here are more info about raspi-config. So here how it looks
one unexpanded image. Actually is the same image, but second partition has a half a blocks
(size). And instead to end of 15130623 sector ends 8110079.
Why I am writing this is because reading some other manuals on the web you may find that you image does not end at the last sector, but end at the half of sectors or somewhere else. Any way keep that in mind.
Check available space on target SD card
Next step is to check available space on target SD card - where you are going to write image.
So insert SD card into SD card reader/dongle and then plug it into USB on the same Linux machine.
Then you need to verify to which device it maps. For that purpose run dmesg | tail
and check output.
As you see my device is attached to /dev/sdb, you may be attached to sda, sdc, etc. If you pay attention to those messages you will see 15126528 512-byte logical blocks: (7.74 GB/7.21 GiB) line. So that’s the number of sectors and, block size and total size of target SD card. But you can check it further with fdisk. Note that in order to access /dev/sdb/ you will need of sudo.
Calculate new size and shrink image file
As you see the most important information that we focus to the moment is sectors - 15130624 - 15126528 = 4096 sectors. Remember that number as we are going to use it couple of times.
Next step is to mount image file with command - losetup
So image file is mounted to /dev/loop0. You can run fdisk
on it and you will
see the same result that from run fdisk on image file itself.
As you see in this output (and on previous as well) we have two partitions in the file. The first one is boot one. Which we are not going to touch. The second one is data partition - /dev/loop0p2 which we are going to shrink. For that purpose we need to mount only that partition. We are going to use -o or offset parameter of losetup command. But first we need to calculate offset. Get the start sector of second partition which in my case is 122880 and multiply it by 512.
Before to mount second partition we need to unmount image file. First command is to unmount and second to mount only partition that we want to shrink.
Now we can run some commands to check file system for example e2fsck.
When I run this command I got some errors. Of course I want them to be fixed. So when program asks me I confirm.
Next step is to shrink file system. For that purposes we are going to use resize2fs command. It accepts new size with bytes, megabytes, gigabytes or sectors. Sectors is easy, because we just know the size of sectors of old, new one and difference. So Start sector is 122880, End sector is 15130623. So the size in sector is:
Difference is 4096 sectors. So we need to subtract from size that number.
And we need to execute the command.
Now we can check again for errors file system.
Finally do not forget to unmount file.
At that point we are ready to write image from Linux. But still we will not be able to write it with Win32 Disk Imager. Even if we write it from Linux we will get error that size of image file is bigger that the SD card. But it will written and it will work. And second problem is that partition info is not correct. It will work, but if you try to edit with gparted for example it will give you some strange errors. So let’s see how to fix those problems.
Fix partition info
First we need to mount entire file again, as we did it in the beginning.
Then we need to run command that shows partition info.
Remember number 15007744, so we need to subtract from it again 4096 and to save back partition info. For that purpose output that info into file. Then edit that file and then run command to save it back.
Edit partition.txt and replace 15007744 with 15003648 (which is 15007744 - 4096). So file will look like this:
And final command is to import back this partition info with the same command.
So now problem with partition info is fixed and gparted will not complain if you want to edit partitions with it. But as I said you can skip this step. It will work without it.
Final step is to unmount file.
Shrink the file size
To the moment we shrink file system size. But size of image file is still the same. Trying to write it to SD card with Win32 Disk Imager will not be possible. Still you can write it to the SD card with Linux dd command. It will give you an error, you can ignore it and it will work. Here is the command to write file to SD card and you can see the error. But as you see it copy file up to size that can fit to SD card.
To avoid that we need to shrink the file size itself. For that purpose we are going to use truncate command. Remember 4096 sectors, multiply them by 512 and that is size that we need to subtract from current size. To check file size type.
Image file size as you see is 7746879488 bytes. New size should be:
And here is the command that you need to execute.
As you see image is truncated to it’s new size. As I said this step is not necessary. But it will give you possibility to write image with Win32 Disk Imager or with dd Linux command without giving you warnings. Format of command is simple. From where to copy to where to copy and parameter bs specifies block size - it is not mandatory. If not specified it will read and write block by one by one. Setting it to 4 megabytes will speed up a little bit process. What we are executing here is copy file Raspberry-Image-8G.img to device /dev/sdb using block copy. And because size of file should be the same as size of target SD card we will not get error at the end.
At the end you have to run sync command to make sure result of dd command is synced and then you can unplug SD card from Linux box and put it into Raspberry.
Hope this tutorial helps you to understand necessary operation to works with SD cards and file systems on Linux. Principles are the same and you can apply it over any other media - flash drive, hard drive, etc.