Resizing disk images

This article is based on the original article found here: original

Sometimes you've made a Disk image of a SDcard from your raspberry and want to put that image on another SD card. What can you do if this other SD card is just a bit smaller that the original image. You should make it smaller. Fortunately this is not difficult on Ubuntu. We need the image file (in my example Raspberry.img) and some software.

In a terminal install the software:

$ sudo apt install gparted coreutils

to install the software. The other software should be installed on a standard Ubuntu installation

Creating loopback device

GParted operates on devices, not simple files like images. This is why we first need to create a device for the image. We do this using the loopback-functionality of Linux. Enter the terminal in the folder where the img file is.

First we will enable loopback if it wasn't already enabled:

Now we can request a new (free) loopback device:

sudo losetup -f

This will return the path to a free loopback device. In this example this is /dev/loop4.

Next we create a device of the image:

sudo losetup /dev/loop4 Raspberry.img

Now we have a device /dev/loop4 that represents Raspberry.img. We want to access the partitions that are on the image, so we need to ask the kernel to load those too:

sudo partprobe /dev/loop4

This should give us the device /dev/loop4p2, which represents the larger partition in Raspberry.img. We do not need this device directly, but GParted requires it.

Resize partition using GParted

Next we can load the device using GParted:

$ sudo gparted /dev/loop4

Now notice a few things:

    • There are two partitions. p1 and p2

    • The partitions allocates almost the entire disk/device/image.

    • The larger partition is filled partly.

We want to resize this larger partition so that is fits it content, but not more than that.

Select the partition and click Resize/Move.

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. The filesystem is probably linux and not NTFS sindce that is only used bij Windows and not by the Raspberry PI.

Finally press Resize/Move. You will return to the GParted window.

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, most of the time it finishes quickly.

Now you can close Gparted, or use it to extract the data needed to truncate the actual img file.

Find the actual size of the image using Gparted

In Gparted, you can select the larger resized partition. Choose information and look for Last sector (in Dutch Laatste sector)

take note of that number, since we're going to need that. (in this example (Laatste sector))

Now trigger the information about the image and look for Sectorsize (in Dutch Sectorgrootte) which in this example is 512

Take note of that number to and you may close GParted.

Now we don't need the loopback-device anymore, so unload it:

sudo losetup -d /dev/loop4

Now you can skip to the last chapter resizing the image.

Find the actual size of the image using fdisk

If finding the information in Gparted didn't work, you may use the commandline instead using fdisk:

fdisk -l myraspbianimage.img

Here we will see an output similar to the following:

Note two things in the output:

    • The partition ends on block 59553791 (shown under Einde, End in English)

    • The block-size is 512 bytes (shown as sectors of 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 (59553791) will differ for you. The numbers mean that the parition ends on byte 59553791*512 of the file. After that byte comes the unallocated-part. Only the first 59553791*512 bytes will be useful for our image.

Resizing the image

Next we shrink the image-file to a size that can just contain the partition. For this we will use the truncate command With the truncate command need to supply the size of the file in bytes. The last block was 59553791 and block-numbers start at 0. That means we need (59553791+1)*512 bytes. This is important, else the partition will not fit the image. So now we use truncate with the calculations:

truncate --size=$[(59553791+1)*512] Raspberry.img

Now copy the new image over to your microSD card, where it should act exactly the same as the old/big image.

PiShrink

PiShrink is a bash script that automatically shrink a pi image that will then resize to the max size of the SD card on boot. This will make putting the image back onto the SD card faster and the shrunk images will compress better.

Usage

sudo pishrink.sh [-s] imagefile.img [newimagefile.img]

If the -s option is given the script will skip the autoexpanding part of the process. If you specify the newimagefile.img parameter, the script will make a copy of imagefile.img and work off that. You will need enough space to make a full copy of the image to use that option.

Prerequisites

If you are trying to shrink a NOOBS image it will likely fail. This is due to NOOBS paritioning being significantly different than Raspian's. Hopefully PiShrink will be able to support NOOBS in the near future.

If using Ubuntu, you will likely see an error about e2fsck being out of date and metadata_csum. The simplest fix for this is to use Ubuntu 16.10 and up, as it will save you a lot of hassle in the long run.

Installation

wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh chmod +x pishrink.sh sudo mv pishrink.sh /usr/local/bin

Example

[user@localhost PiShrink]$ sudo pishrink.sh pi.img e2fsck 1.42.9 (28-Dec-2013) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information /dev/loop1: 88262/1929536 files (0.2% non-contiguous), 842728/7717632 blocks resize2fs 1.42.9 (28-Dec-2013) resize2fs 1.42.9 (28-Dec-2013) Resizing the filesystem on /dev/loop1 to 773603 (4k) blocks. Begin pass 2 (max = 100387) Relocating blocks XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Begin pass 3 (max = 236) Scanning inode table XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Begin pass 4 (max = 7348) Updating inode references XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX The filesystem on /dev/loop1 is now 773603 blocks long. Shrunk pi.img from 30G to 3.1G