I installed Raspbian to a 16 GB card and expanded the filesystem. When I made a dd backup of the card, the .img file output was ~16 GB. Most of it is unused space in the ext4 partition—I'm only using like 2.5 GB in that partition. (There are two partitions—the first is FAT for boot and the second is ext4 for rootfs.) I'd like to shrink the backup.img file which resides on an Ubuntu 16.04 Sever installation (no GUI) so that I can restore the image to a card of smaller size (say 8GB for example).

So far, I have mounted the ext4 partition to /dev/loop0 by using the offset value provided to me by fdisk -l backup.img. Then I used e2fsck -f /dev/loop0 and then resize2fs -M /dev/loop0 which appeared to shrink the ext4 fs... am I on the right track? I feel like parted might be next, but I have no experience with it.

How do I accomplish this using only cli tools?


Here is the output from running fdisk -l backup.img:

Disk backup.img: 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: 0x79d38e92

Device        Boot  Start      End  Sectors  Size Id Type
backup.img1 *      8192   124927   116736   57M  e W95 FAT16 (LBA)
backup.img2      124928 31116287 30991360 14.8G 83 Linux

I can confirm you are in the right track shrinking that filesystem; fdisk/parted is next. The tricky part is getting it right next to the size of the new filesystem,do your math or leak a hundred KB more just to be safe. You can adjust it later on the new card if need be.

The order is normally: umount, resize, fdisk/parted, partprobe, fsck, and mount to check all is ok. As the partition you are resizing is less than 2T, you can use either fdisk or parted.

The resize process has to come first, as you won't be able to shrink the partition reliably while the filesystem still claims the space you need to reclaim. After you need to shrink the partition once again for consistency, and for not having the remaining space you want to rid off "booked" for use. The filesystem as to come last to make the filesystem structure consistent with the new size.

I will leave these RH articles. It is missing the partprobe, as the new partition size is not always recognised immediately or by older kernels.

How to Shrink an ext2/3/4 File system with resize2fs

How to Resize a Partition using fdisk

Your missing steps are:

sudo fdisk /dev/loop
p     - to check for partition number (probably 2)
d     - to delete
2     - partition 2
n     - new partition
p     - primary
ENTER - default beginning
+new size -  smaller card size
w      - write it

sudo partprobe /dev/loop

To finish it off, you umount the image file; as the extra size is no longer marked as used both by the filesystem and the partition size in your file image, the operation system won't try to use that space. So it can be truncated safely to the intended size:

truncate -s 8GB fileName

To use the appropriate sizes, as I am lazy, I would shring the filesystem to something less than what I need (i.e. size of new partition - 400k, and then expand it again after I shrink the partition), and would create the partition with the needed size (8GB-2048(2K) for possible 1st partition padding-minus the size of the 1st partition). Not much math involved.

For calculating it properly, please do have a look:

How To Resize ext3 Partitions Without Losing Data

  • Won't I still need to truncate the backup.img file after everything? I am trying to get an understanding of the entire process. I have already done a lot of Googling, including finding those articles you linked to, but I don't presently have the confidence that comes from understanding these tools and their purposes. – jsejcksn Apr 25 '16 at 9:05
  • Yes, obviously...nevertheless if you dd it after all these operation without truncating, the job is already done. If you want to understand it better, do a copy of the file, and perform the process. If anything goes wrong, you just need to copy it over and start the process again. – Rui F Ribeiro Apr 25 '16 at 9:19
  • Ok, so how about that last step? How does truncating work? Will you please add that to your answer? – jsejcksn Apr 25 '16 at 9:22
  • I guess what I meant was this: how do I truncate the backup.img so that it is the minimum size of the partitions and filesystems inside it? – jsejcksn Apr 25 '16 at 9:27
  • No, I mean... how do I calculate that / what value do I use? Do I use the final End sector from the last partition returned by fdisk -l backup.img or do I use that sector +1 byte or what? – jsejcksn Apr 25 '16 at 9:33

What about using the Automatic RPi Image Downsizer?

You can as well take a look at the code to see what is going on.

if [[ ! $(whoami) =~ "root" ]]; then
echo ""
echo "**********************************"
echo "*** This should be run as root ***"
echo "**********************************"
echo ""

if [[ -z $1 ]]; then
echo "Usage: ./autosizer.sh "

if [[ ! -e $1 || ! $(file $1) =~ "x86" ]]; then
echo "Error : Not an image file, or file doesn't exist"

partinfo=`parted -m $1 unit B print`
partnumber=`echo "$partinfo" | grep ext4 | awk -F: ' { print $1 } '`
partstart=`echo "$partinfo" | grep ext4 | awk -F: ' { print substr($2,0,length($2)-1) } '`
loopback=`losetup -f --show -o $partstart $1`
e2fsck -f $loopback
minsize=`resize2fs -P $loopback | awk -F': ' ' { print $2 } '`
minsize=`echo $minsize+1000 | bc`
resize2fs -p $loopback $minsize
sleep 1
losetup -d $loopback
partnewsize=`echo "$minsize * 4096" | bc`
newpartend=`echo "$partstart + $partnewsize" | bc`
part1=`parted $1 rm 2`
part2=`parted $1 unit B mkpart primary $partstart $newpartend`
endresult=`parted -m $1 unit B print free | tail -1 | awk -F: ' { print substr($2,0,length($2)-1) } '`
truncate -s $endresult $1
  • I asked how to go about accomplishing my goal because I want to understand the process. – jsejcksn Apr 25 '16 at 9:01
  • Well the steps in the script are self explanatory and a good way to learn independently (autodidactic approach), which at the end of the day, is what will reside in your memory for a longer period of time. – marc Apr 25 '16 at 9:03
  • I realize that I could read every manpage for every command installed and that would sort my issue, but that's why I'm posting on SE: to get help from others instead of doing that or instead of trial/error. I'm looking for instruction / teaching. I appreciate that you Googled for me and copy-pasted. – jsejcksn Apr 25 '16 at 9:07
  • I respect your approach. – marc Apr 25 '16 at 9:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.