Shrinking an SD card image using Linux shell commands
Published on Oct 09, 2021.
I really enjoy messing with Raspberry Pi computing systems and have several running inside my home, either feeding my stereo system with music or keeping my personal data in sync. To make backups or creating clones of existing systems, I can always stick the SD card running the operating system of the Raspberry Pi into my laptop and copy the entire content onto my hard disk. On those occasions it is sometimes nice to be able to shrink the resulting image down to the amount of actual data contained within (instead of the size of the SD card). I prefer to use command-line tools as they are easier to document and control.
This post is part of the notes-to-future-self series: I will probably want to do this again, so better write down how I worked things out the first time! ;)
A great help was this article on which much of this post is based upon. I managed to simplify a couple of things, however, sticking with only command-line tools.
First, I made a copy of the SD card using dd
. Now I want to shrink part of the image containing the root file system. I can list the partitions contained in the image using fdisk
:
fdisk -l /home/hanno/rasppi_20210429_SHRUNK.img
Disk /home/hanno/rasppi_20210429_SHRUNK.img: 29,81 GiB, 31992053760 bytes, 62484480 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: 0xf16f32c5 Device Boot Start End Sectors Size Id Type /home/hanno/rasppi_20210429_SHRUNK.img1 8192 98045 89854 43,9M c W95 FAT32 (LBA) /home/hanno/rasppi_20210429_SHRUNK.img2 98304 62484479 62386176 29,8G 83 Linux
Using the --partscan
option of losetup
, we can access these partitions directly via a loopback device and thus making them individually visible to the operating system:
losetup --show -f --partscan /home/hanno/rasppi_20210429_SHRUNK.img
/dev/loop22
ls /dev/loop22*
/dev/loop22 /dev/loop22p1 /dev/loop22p2
On these partitions reside the filesystems that contain the actual data. Find out what the minimum size of the image would be (i.e. the actual data contained within):
sudo resize2fs -P /dev/loop22p2
resize2fs 1.45.5 (07-Jan-2020) Estimated minimum size of the filesystem: 615955
This is in file-system block size which are 4 kB large. Add a little and use this number to shrink the filesystem down to this size:
sudo e2fsck -p -f /dev/loop22p2 && sudo resize2fs /dev/loop22p2 750000
rootfs: 61061/1884960 files (0.1% non-contiguous), 544080/7798272 blocks resize2fs 1.45.5 (07-Jan-2020) Resizing the filesystem on /dev/loop22p2 to 750000 (4k) blocks. The filesystem on /dev/loop22p2 is now 750000 (4k) blocks long.
Now we can be sure that all the data is contained within those limits. Time to reduce the partition boundaries to these values.
We can use fdisk
on the main
loopback device to delete the 2nd partition and recreate it with the same start
and the new end (i.e. 750000*4 kB):
echo +$((750000*4))K
+3000000K
The plus in the beginning is important as it indicates a relative number and not an absolute number.
Run fdisk
:
fdisk /dev/loop22
Press d
, select the 2nd partition, confirm, press n
and follow the prompts and enter the values above.
Then, remove the loopback devices again:
sudo losetup -d /dev/loop22*
losetup: /dev/loop22p1: failed to use device: No such device losetup: /dev/loop22: detach failed: No such device or address losetup: /dev/loop22p2: failed to use device: No such device losetup: /dev/loop22: detach failed: No such device or address
Looks like they were removed already. Let’s look at the new partition table:
fdisk -l /home/hanno/rasppi_20210429_SHRUNK.img
Disk /home/hanno/rasppi_20210429_SHRUNK.img: 29,81 GiB, 31992053760 bytes, 62484480 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: 0xf16f32c5 Device Boot Start End Sectors Size Id Type /home/hanno/rasppi_20210429_SHRUNK.img1 8192 98045 89854 43,9M c W95 FAT32 (LBA) /home/hanno/rasppi_20210429_SHRUNK.img2 98304 6098943 6000640 2,9G 83 Linux
It worked so far! The total image is still 30 GB large but the data partition is only about 3 GB. Now we can remove everything from the image until the end sector of the 2nd partition as provided in the fdisk
output above:
END=6098943
truncate -s $(((END+1)*512)) /home/hanno/rasppi_20210429_SHRUNK.img
ls -lh /home/hanno/rasppi_20210429_SHRUNK.img
-rw-r--r-- 1 hanno hanno 3,0G jul 8 23:33 /home/hanno/rasppi_20210429_SHRUNK.img
And that is it, the file is a mere 3 GB in size now! :)
Of course, from within the Raspian OS, you can easily stretch the system again to fill any size SD card from within the configuration tool raspi-config
.
Tags: raspberrypi, linux