First we will create a .img
file of your SD card image.
Linux users can just use dd (the same command you probably used to get the image onto the SD card in the first place) or the dcfldd command (which shows the progress of the operation unlike dd). For example, to copy all contents off the device that represents your SD card into an .img file in your home directory:
You should find out the block size of your sd card first (using an improper block size can lead to issues later on... TRUST)
$ sudo fdisk -l /dev/mmcblk0
Please check the SD Card device, it might be something like
/dev/mmcblk0
or/dev/sdX
. In the following example we are using/dev/mmcblk0
.
Now, look at this line from the output of the previous command. It will determine what we should use as the bs (block size, not bullsh!t):
Units: sectors of 1 * 512 = 512 bytes
So, bs=512 would be the proper syntax in this instance. Other examples could be: bs=2MB (for block size = 2 Megabytes), or bs=4MB (for block size = 4 Megabytes), without specification, dd/dcfldd default to the bytes value.
And finally, to copy all contents off the device that represents your SD card into an .img
file in your home directory:
$ sudo dd if=/dev/mmcblk0 of=$HOME/sd_image.img bs=512
The above command may take some time depending on the size of your SD card.
Now to resize the SD card we will use resize2fs
. resize2fs
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.
First we will enable loopback if it wasn't already enabled:
$ sudo modprobe loop
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/loop0
.
Next we create a device of the image:
$ sudo losetup /dev/loop0 sd_image.img
Now we have a device /dev/loop0
that represents sd_image.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/loop0
This should give us the device /dev/loop0p1
, which represents the first partition in sd_image.img
.
Here we will resize the second part
loop0p2
If the partition the file system is on is currently mounted, unmount it.
For example
$ sudo umount /dev/loop0p2
Run fsck on the unmounted file system.
For example
$ sudo e2fsck -f /dev/loop0p2
e2fsck 1.42.13 (17-May-2015)
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/loop0p2: 6990/242880 files (0.0% non-contiguous), 78511/971008 blocks
Now we resize our file system with resize2fs
. Shrink the file system with the resize2fs /dev/device size
command.
For example
$ sudo resize2fs /dev/loop0p2 500M
resize2fs 1.42.13 (17-May-2015)
Resizing the filesystem on /dev/loop0p2 to 128000 (4k) blocks.
The filesystem on /dev/loop0p2 is now 128000 (4k) blocks long.
Accepted size units for file system block sizes are:
S - 512 byte sectors
K - kilobytes
M - megabytes
G - gigabytes
Please take note of the amount of blocks (128000) and their size (4k). We need that soon.
Now we delete our /dev/loop0p2 partition (don't be afraid, no data will be lost) and create a new, smaller one (but still big enough to hold our resized file system!). We can do this with fdisk
:
$ sudo fdisk /dev/loop0
Its
loop0
notloop0p2
Type m
to get a list of all commands or p
to print the partition table.
Command (m for help): p
Disk /dev/loop0: 3.7 GiB, 3995074560 bytes, 7802880 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: 0x4474fba8
Device Boot Start End Sectors Size Id Type
/dev/loop0p1 2048 34815 32768 16M c W95 FAT32 (LBA)
/dev/loop0p2 34816 7802879 7768064 3.7G 83 Linux
Now use d
to delete the partition. Here we will delete the second partition.
Command (m for help): d
Partition number (1,2, default 2): 2
Partition 2 has been deleted.
Now we will create a new partition with n
command.
Give it a partition number 2.
For first sector user default. For the last sector we have to calculate it. Fortunately, we can specify the size in kilobytes (K), so we calculate the size like this:
We multiply the amount of blocks from the resize2fs
output (128000) by the size of a block (4k), and to go sure the partition is big enough, we add 3 to 5% to it (3% was enough for me, but if you want to go sure take 5%):
128000 * 4k * 1.03 = 527360k
So we prepend that value with a +
sign and replace the small k
with a capital one (K
) and enter it:
Command (m for help): n
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 2
First sector (34816-7802879, default 34816):
Last sector, +sectors or +size{K,M,G,T,P} (34816-7802879, default 7802879): +527360K
Created a new partition 2 of type 'Linux' and of size 515 MiB.
Now let's write our new partition table and exit fdisk:
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Re-reading the partition table failed.: Invalid argument
The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8).
Now we don't need the loopback-device anymore, so unload it:
$ sudo losetup -d /dev/loop0
Now that we have all the important data at the beginning of the image it is time to shave of that unallocated part. We will first need to know where our partition ends and where the unallocated part begins. We do this using fdisk:
$ fdisk -l sd_image.img
Here we will see an output similar to the following:
Disk sd_image.img: 3.7 GiB, 3995074560 bytes, 7802880 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: 0x4474fba8
Device Boot Start End Sectors Size Id Type
sd_image.img1 2048 34815 32768 16M c W95 FAT32 (LBA)
sd_image.img2 34816 1089535 1054720 515M 83 Linux
Note two things in the output:
- The partition ends on block 1089535 (shown under End)
- 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 (1089535) will differ for you. The numbers mean that the parition ends on byte 1089535*512
of the file. After that byte comes the unallocated-part. Only the first 1089535*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 1089535 and block-numbers start at 0. That means we need (1089535+1)*512
bytes. This is important, else the partition will not fit the image. So now we use truncate with the calculations:
$ sudo truncate --size=$[(1089535+1)*512] sd_image.img
Now you can use this image.
More Links: