Context
I have a 16 GB SD card with a Linux based OS for a Raspberry Pi.
Most of the space is empty.
I want to share the SD .img
with other people but if I use the command
dd if=/dev/sdXX of=/home/user123/SD.img
it will create a 16 GB image. Too big.
Question
How can I re-size a 16GB SD card image into a smaller 4GB?
I have tried with GParted: it creates a partition with 4GB with no problem, however the whole .img
of the SD card continues to be 16 GB with 12 GB of unallocated space.
I have read the question and answer Cloning multiple partitions in Ubuntu, but I still cannot re-size the 16GB SD card into a 4GB one.
More info
~$ lsblk
...
sdc 8:32 1 14,9G 0 disk
├─sdc1 8:33 1 100M 0 part
└─sdc2 8:34 1 4G 0 part
~$ sudo fdisk -l /dev/sdc
Disk /dev/sdc: 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: 0xf8a631ce
Device Boot Start End Sectors Size Id Type
/dev/sdc1 * 2048 206847 204800 100M c W95 FAT32 (LBA)
/dev/sdc2 206848 8595455 8388608 4G 83 Linux
Any advice is appreciated!
Please note: as observed by Melebius in a comment, the right word to use is shrink:
You cannot resize an SD card as it is hardware with a given capacity that cannot be changed. You clearly want to shrink an SD card image.
Best Answer
This article gives a solution that solves my problem. It is quite similar to the other one, but it better explains how to calculate and which meaning have the numbers and the partitions.
The key information was the use of the command
truncate
. Following the full solution in order to not lose the answer.A preliminary step consists in cloning the SD card in your PC:
use
lsblk
to see which devices are available and if their partitions are mountedunmount all partitions of the device you want to copy on your pc. For example:
create a copy of the whole sd card with all the partitions unmounted
Shrinking images on Linux
Context of the problem:
Having a
myimage.img
bigger then the hardware support (if it is smaller there should be no problem; however, using the same strategy, you can better fit the image in the hardware support).The secret is to use standard Linux tools and instruments: GParted,
fdisk
andtruncate
.Requirements:
.img
you want to shrink (myimage.img
in this example)Creating loopback device:
GParted is an application typically used to manage partition tables and filesystems. In order to shrink the image, GParted is going to be used along the first part of the answer.
Let's enable enable the loopback:
Let's request a new (free) loopback device:
The command returns the path to a free loopback device:
Let's create a device of the image:
The device
/dev/loop0
representsmyimage.img
. We want to access the partitions that are on the image, so we need to ask the kernel to load those too:This should give us the device
/dev/loop0p1
, which represents the first partition inmyimage.img
. We do not need this device directly, but GParted requires it.Resize partition using GParted:
Let's load the new device using GParted:
When the GParted application opens, it should appear a window similar to the following:
Now notice a few things:
We want to resize this partition so that is fits its content, but not more than that.
Select the partition and click Resize/Move. A window similar to the following will pop up:
Drag the right bar to the left as much as possible.
Note that sometimes GParted will need a few MB extra to place some filesystem-related data. You can press the up-arrow at the New size-box a few times to do so. For example, I pressed it 10 times (=10MiB) for FAT32 to work. For NTFS you might not need to at all.
Finally press Resize/Move. You will return to the GParted window. This time it will look similar to the following:
Notice that there is a part of the disk unallocated. This part of the disk will not be used by the partition, so we can shave this part off of the image later. GParted is a tool for disks, so it doesn't shrink images, only partitions, we have to do the shrinking of the image ourselves.
Press Apply in GParted. It will now move files and finally shrink the partition, so it can take a minute or two, but most of the time it finishes quickly. Afterwards close GParted.
Now we don't need the loopback-device anymore, so unload it:
Shaving the image:
Now that we have all the important data at the beginning of the image it is time to shave off that unallocated part. We will first need to know where our partition ends and where the unallocated part begins. We do this using
fdisk
:Here we will see an output similar to the following:
Note two things in the output:
End
)1 * 512
)We will use these numbers in the rest of the example. The block-size (512) is often the same, but the ending block (9181183) will differ for you. The numbers mean that the partition ends on byte 9181183*512 of the file. After that byte comes the unallocated-part. Only the first 9181183*512 bytes will be useful for our image.
Next we shrink the image-file to a size that can just contain the partition. For this we will use the
truncate
command (thanks uggla!). With the truncate command need to supply the size of the file in bytes. The last block was 9181183 and block-numbers start at 0. That means we need (9181183+1)*512 bytes. This is important, else the partition will not fit the image. So now we use truncate with the calculations: