Hacking .img/.sdcard files

Published on February 24, 2015

Archived Notice

This article has been archived and may contain broken links, photos and out-of-date information. If you have any questions, please Contact Us.

We ship around lots of images for use on SD cards, SATA drives, or USB sticks. Some of them are publicly available and listed in our i.MX6 Builds page, but others are used during development and testing of custom boards or customer-specific things.

Our convention is to use the name .img or .sdcard for files that comprise a partition table and one or more file-system partitions, and have repeated instructions like these about how you can restore them to SD card.

You can also access the internals on a development machine though, and in this post, we'll describe some of the tools we use to create, update, and access the content of these image files without going through the very slow process of placing them on an actual SD card.

Tools and image

The tools used in this post are all documented using man, but it's easier to link to web pages:

We'll use the console image (20150126-nitrogen-3.10.17_1.0.2_ga-trusty-en_US-lxde_armhf.img.gz) from Laci's Cell modem post as an example.

Basics of reading

To access the internals of an SD card image, you'll need to de-compress the image: using gunzip. We'll rename the image in the process to something shorter (trusty).

~/Downloads$ ls -l 20150126-nitrogen-3.10.17_1.0.2_ga-trusty-en_US-lxde_armhf.img.gz -rw-rw-r-- 1 ericn ericn 784331493 Feb 24 12:09 20150126-nitrogen-3.10.17_1.0.2_ga-trusty-en_US-lxde_armhf.img.gz ~/Downloads$ gunzip 20150126-nitrogen-3.10.17_1.0.2_ga-trusty-en_US-lxde_armhf.img.gz ~/Downloads$ mv 20150126-nitrogen-3.10.17_1.0.2_ga-trusty-en_US-lxde_armhf.img trusty.img ~/Downloads$ file trusty.img trusty.img: x86 boot sector ~/Downloads$ fdisk -l trusty.img Disk trusty.img: 3774 MB, 3774873600 bytes 239 heads, 36 sectors/track, 856 cylinders, total 7372800 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 Disk identifier: 0x6b5130d0 Device Boot Start End Blocks Id System trusty.img1 2048 7372799 3685376 83 Linux

In English, the file command recognizes the file as containing a DOS-style partition table (which originated on x86) and the fdisk tool shows a single partition.

The partition starts at block number 2048 and ends at block number 7372799. Doing the math for you, this starts at an offset of 1MiByte and the total size is 3600 MiBytes.

Note that you need to be careful in the use of various utilities because sometimes they refer to Megabytes instead of Mibibytes. For example, the first line of output from fdisk above says 3744 MB and is referring to Megabytes (1 Million bytes). Google if you don't understand the distinction.

This image shows our convention of producing images that are 3600 MiB long to account for variations in 4GB cards.

Loopback mounts

Okay, so now we know what's inside the .img file, but don't have access to the internals. This is where the losetup tool comes into play. Since Linux can only mount a block device, we can use a Loopback device to point at offset 1MiB (1048576 bytes) into the file with a size of 3599 MiB (3773825024 bytes):

~/Downloads$ loopdev=`sudo losetup -f`; ~/Downloads$ echo "loop device is $loopdev" loop device is /dev/loop0 ~/Downloads$ sudo losetup -o 1048576 --sizelimit 3773825024 $loopdev trusty.img ~/Downloads$ udisks --mount $loopdev Mounted /org/freedesktop/UDisks/devices/loop0 at /media/trusty ~/Downloads$ ls /media/trusty/ 6x_bootscript boot initrd.img mnt run tmp var 6x_bootscript.txt dev lib opt sbin uEnv-nit6xlite.txt vmlinuz 6x_upgrade etc lost+found proc srv unit_tests work bin home media root sys usr

Note that the losetup -f command above finds the next available loopback device on your system, and we use that as the name of the device through the variable loopdev.

So in a few commands, we now have access to the internals of the .img file. This in itself is useful for examining the content, or even for tweaking something like a boot script. We mounted the filesystem as read-write, so both are possible.

We do need to take care in unmounting the filesystem and freeing up the loopback device, but that's also not hard:

~/Downloads$ sudo umount $loopdev ~/Downloads$ sudo losetup -d $loopdev

Basics of creation

Given the tools above, you may already have figured out how to create an image of your own, but we'll walk through a simple example. The process involves three primary steps:

  • Create the .img file with the appropriate size using dd
  • Create the partition table using fdisk
  • Create filesystem(s) using loopback device(s)
~$ dd if=/dev/zero of=my.img bs=1M count=3600 3600+0 records in 3600+0 records out 3774873600 bytes (3.8 GB) copied, 41.9144 s, 90.1 MB/s ~$ fdisk my.img Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel Building a new DOS disklabel with disk identifier 0x4c145691. Changes will remain in memory only, until you decide to write them. After that, of course, the previous content won't be recoverable. Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite) Command (m for help): n Partition type: p primary (0 primary, 0 extended, 4 free) e extended Select (default p): p Partition number (1-4, default 1): Using default value 1 First sector (2048-7372799, default 2048): Using default value 2048 Last sector, +sectors or +size{K,M,G} (2048-7372799, default 7372799): Using default value 7372799 Command (m for help): p Disk my.img: 3774 MB, 3774873600 bytes 255 heads, 63 sectors/track, 458 cylinders, total 7372800 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 Disk identifier: 0x4c145691 Device Boot Start End Blocks Id System my.img1 2048 7372799 3685376 83 Linux Command (m for help): w The partition table has been altered! Syncing disks. ~$ loopdev=`losetup -f` ~$ sudo losetup -o 1048576 --sizelimit 3773825024 $loopdev my.img ~$ sudo mkfs.ext4 -L myrootfs $loopdev mke2fs 1.42.9 (4-Feb-2014) Discarding device blocks: done Filesystem label=myrootfs OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 230608 inodes, 921344 blocks 46067 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=943718400 29 block groups 32768 blocks per group, 32768 fragments per group 7952 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736 Allocating group tables: done Writing inode tables: done Creating journal (16384 blocks): done Writing superblocks and filesystem accounting information: done ~$ sudo partprobe ~$ udisks --mount $loopdev Mounted /org/freedesktop/UDisks/devices/loop0 at /media/myrootfs ~$ ls /media/myrootfs/ lost+found ~$ sudo umount $loopdev ~$ sudo losetup -d $loopdev

Of course, a typical use would actually populate the filesystem after using udisks to mount the loopback device, but this is sufficient to understand the basics.

Use in the wild

We have at least one example of how these tools can be used in our Android KK tree. The mksdimage.sh script uses these tools to create an .img file from an Android build tree.

Other tidbits

Note that the tools above are only some of those available in Linux to manipulate images. Others that are useful in other contexts include:

These others are especially useful when building scripts to automate the process.