Mar 042013
 

**Update**
I have now built a script to do this automatically.
The script will minimise the size as much as possible.
Script can be found here


I recently had to resize a Raspbian Server Edition image into a 1 gigabyte image. As I didn’t actually have a 1 gigabyte SD card to use as a template, I generated my own by resizing the original 2 gigabyte image.

This was done on another computer, but this can also be done on the Pi itself, and you can even flash the resulting image to an SD card if you have a USB SD Card reader on the Pi.

Also, most commands will need to be run as root, or use sudo to run the commands.

Step 1 : Mounting the image

First thing I did was make a copy of the 2gb image to work on, this is not essential if you downloaded the image originally, but I’m working on the original RSE image.

# cp RSEv2.3.img RSE1g.img

Similar to part 1, we need to mount the image via loopback.

# losetup -f --show RSE1g.img

This will mount the image file as a loopback device, and show you which one it was mounted as. By default, it should be /dev/loop0

Step 2: Resizing the Partition

Once the image is mounted, we then need to run parted on the image file, and get it to print out the current partitions.

# parted /dev/loop0
GNU Parted 2.3
Using /dev/loop0
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted)

Running the print command will output the current setup.

(parted) print
Model: Loopback device (loop)
Disk /dev/loop0: 2003MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number Start End Size Type File system Flags
1 4194kB 62.9MB 58.7MB primary fat16 lba
2 62.9MB 1940MB 1877MB primary ext4

(parted)

As you can see, the 2nd partition, which is the linux partition, is 1877 megabytes. To resize the partition, we need to remove it, and recreate it with a new size.

Running the command rm 2 will remove the 2nd partition.

(parted) rm 2

To recreate it, we need to use mkpart command, and specify that we will be creating it as a primary partition, starts at 62.9MB, and ends at 900MB to give us a partition of 837 MB.

(parted) mkpart primary 62.9 900

Once the partition has been created, running print again will show us the new setup.

(parted) print
Model: Loopback device (loop)
Disk /dev/loop0: 2003MB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number Start End Size Type File system Flags
1 4194kB 62.9MB 58.7MB primary fat16 lba
2 62.9MB 900MB 837MB primary ext4

We will also need to get the amount of sectors in the new partition so we can resize the filesystem to the right size later. To do that, we change the units to sectors, and then run the print command again

(parted) unit s

Now when we run the print command, the partitions will show up with sectors as the units instead

(parted) print
Model: Loopback device (loop)
Disk /dev/loop0: 3911680s
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number Start End Size Type File system Flags
1 8192s 122879s 114688s primary fat16 lba
2 122880s 1757183s 1634304s primary ext4

We’ll need to take a note of the size of the number 2 partition (1634304 sectors) and the sector size (512 bytes), and also the start of the partition (sector 122880).

Step 3: Resizing the Filesystem

Once the partition has been resized, we will then need to resize the filesystem that resides in the partition.

We need to calculate where the partition starts so we can mount the specific partition rather than the whole image. To calculate it, we take the starting sector, and multiply it by the sector size.

I’m using bc to do the calculation here

# echo '122880 * 512' | bc
62914560

So to mount the partition itself, we need to mount the image with an offset. This should mount it on /dev/loop1

# losetup -f --show -o 62914560 RSE1g.img
/dev/loop1

Before we can resize the filesystem, we need to check it for errors first. We’ll need to force it as the filesystem is meant to be clean.

# e2fsck -f /dev/loop1
e2fsck 1.42.5 (29-Jul-2012)
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: 28754/114688 files (0.1% non-contiguous), 153181/458240 blocks

Once the filesystem has been verified as clean, we can then use resize2fs to resize the filesystem.
We will need to calculate the size of the new filesystem to resize it correctly. To do that, we need to take the size of the partition in sectors (1634304), and divide by 8 (4KB blocks divided by 512 bytes/sector), assuming we are using 4KB blocks in the filesystem.

# echo '1634304 / 8' | bc
204288

We can use resize2fs now to resize the filesystem to the correct size.

# resize2fs /dev/loop1 204288
resize2fs 1.42.5 (29-Jul-2012)
Resizing the filesystem on /dev/loop1 to 204288 (4k) blocks.
The filesystem on /dev/loop1 is now 204288 blocks long.

Once the resize is done, we can now remove all loopback devices

# losetup -d /dev/loop0 /dev/loop1

Step 4: Resize the image file

Once the resize is all completed, we just need to lop off the end of the image file that has all the free space.
Since the 2nd partition ends at the 900MB mark, we can lop it off right there with the truncate command

# truncate -s 900M RSE1g.img

The filesize will now be 900 Megabytes which is small enough to fit onto any 1GB SD Card.

m4s0n501
Share

  11 Responses to “How To : Resize Partitions in an Image File Part 2”

  1. Doing the filesystem shrink after the partition shrink is DANGEROUS! Always shrink the filesystem first, and then the partition!

    • If I were doing it to more heavily used partition, I would have definitely done that. In this case, it was easier to resize partition to fit on sd card and then resize filesystem.

      Thanks for the tip though !

  2. Hey is it possible to resize the new kali linux for arm raspberry pi to fit on a 4gb sd card?
    the size of the image is 5gb.
    thx.

  3. Are you sure, it is
    # truncate -s 900M RSE1g.img
    on step 4?
    Not
    # truncate -s 900MB RSE1g.img
    ?

    I’m a little confused, because my length 16.0G results in an ‘invalid number’-exception.
    I hoped, this would work, but it doesn’t….

    • Yes, Truncate 900M truncates the file to 900 Real Megabytes.
      Truncate 900MB would truncate it to 900 Decimal Megabytes.

      Check the man page for more details :)

  4. […] เช่นวิธีการในเว็บที่ไปเจอมาครับซึ่งแนะนำวิธีที่จะทำด้วยครับ […]

  5. Hi,

    Cool stuff but I’m running into an issue. I’m trying your script on Ubuntu 14 and it’s erroring out on a 32GB image file. When I manually run parted on the mounted img and print the partitions (first couple steps of this tutorial) I can only see the primary fat16 partition and no other which is resulting in the error. Any thoughts or suggestions?

    Thanks

  6. Didn’t work. I got “superblock could not be read” on the new linux partition. But there is enough information here that I can probably get it to work. I am a little suspicious of the use of MB units in mkpart.

    I am shrinking a 16GB image to just under 8GB so that any 8GB card will hold the image. I resized the fs first, and checked it. I was real careful with all my arithmethic but obviously I went wrong at some point.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>