Exploring .img Files on Linux

| | 0 Comments| 2:39 PM
Categories:

Editor’s note: This tutorial is written using Ubuntu Linux. If you are on a different platform you may need to replace commands such as apt-get with your distributions equivalent.

What’s In Those .img Files?

Have you ever found yourself with an .img file blindly following the tutorial on “flashing” it onto an SD card? Did you know you can create your own disk image files for distributions on thumb drives, SD cards, etc. with minimal effort? This tutorial aims to show you how to:

  • Discover the hidden secrets of a monolithic .img file
  • Mount the partitions in an .img file using losetup, kpartx and mount
  • Create your own .img files and use them as virtual disks
  • Write out your virtual disk image to a thumb drive (or any drive for that matter) for use later

Let’s take a look at the BeagleBone Black Debian distribution file. You can download it with this link.

Once its downloaded you will want to uncompress it with xz --decompress:

If you don’t have xz installed you can obtain it through apt-get install xz-utils.

Once the image is decompressed many tutorials would have you stop there and go straight to using dd to do a byte-by-byte copy onto an SD card, insert into the BeagleBone Black, and boot. We want to examine it a bit further first.

First, we’re going to attach the image file to what is known as a loopback device. The Wikipedia entry introduction is succinct: “In Unix-like operating systems, a loop device is a pseudo-device that makes a file accessible as a block device.” In short, a loop device allows us to present the image file to the operating system as if it were an actual “disk”. To set up the loop device:

We used /dev/loop0 in this example. If /dev/loop0 wasn’t available to us (that is, it was already in use), we could have chosen /dev/loop1, etc. To get a list of the loopback devices that are already in use, one can use losetup -a:

Now /dev/loop0 is attached. What can we do? How about look at the partition table with fdisk?

Whoa! From the output of fdisk we can infer a few things, namely that:

  • There is a partition table present
  • There are two partitions: one with a FAT16 filesystem and another with a “Linux” filesystem

We want some more information about the filesystems on the partitions, so we’re going to utilize the utility kpartx, which according to the man page will Create device maps from partition tables. If you don’t have kpartx on your system, it can be installed with apt-get install kpartx.

To see what kpartx would map, run it with the -l option:

Let’s go ahead and run it and add the maps:

Don’t go looking for loop0p1 in /dev, but rather you should look in /dev/mapper. kpartx will assign the partitions it found and enumerate the partitions in /dev/mapper with the pattern loop0pX where X is the partition number assigned.

Now that the partitions are mapped, let’s examine the filesystems on each partition with file and the --special-files and --dereference options.

From the file manpage: Specifying the -s option causes file to also read argument files which are block or character special files. This is useful for determining the filesystem types of the data in raw disk partitions, which are block special files.

Let’s look at the second partition, which the only thing we know thus far is that it is a “Linux filesystem”.

The second partition is clearly formatted with an ext4 filesystem.

Now that we have our partitions mapped, we can mount them. Create two directories to serve as mountpoints:

Once they are created, mount the filesystems.

It should be quite clear as to why we chose these commands to mount the filesystems. Once they are mounted you can cd into them and look around, change things, etc.

Once you are done and want to “let go” of the .img file, reverse the process with:

Creating Your Own .img Files

Creating your own .img files is quite easy. Let’s say we want to distribute a 2G USB stick that is partitioned with two filesystems: one an ext4 filesystem and the other a btrfs filesystem. On each we’ll store the latest (as of this writing) kernel source code: linux-4.2-rc5.

First, we’ll use the dd utility and the /dev/zero device to create a monolithic 2G file. We’ll use the SI definition for 2 gigabytes, which is 2000000000. This command instructs dd to use /dev/zero as the input file and linuxsource.img as the output file. bs is block size and count is the number of blocks to write. We could have used a block size of 1 but dd is much slower (an inordinate number of minutes compared to 10 seconds with a blocksize of 1000).

Warning: It is a time honored tradition to remind you to treat dd with respect, akin to issuing commands as root. Misused or supplied the wrong arguments dd can seriously ruin your day.

Now we have a raw file, 2G in length, full of zeroes. What do we do with it?

The answer is to present it to the OS as a loop device, and then use fdisk to create a partition table. We effectively created a blank disk drive with nothing on it, so the first step is to put a partition table on the disk.

Now we use fdisk:

Surprise! There’s no partition table on the “disk”. We have to create one and create our partitions. Type n at the Command prompt. n is for new partition.

Hit ENTER to accept the default of a primary partition. Hit ENTER again to accept the default of partition number 1. Hit ENTER again to accept the default of 2048 as the first sector.

Now we will enter +900M as our “last sector”, which is actually applying a size of 900MB for the partition. Here is what the full sequence looks like for creating our first partition:

Let’s create a second partition while we are at it, but if you are curious, you can press p here to print out what the partition will look like when its written.

Create the second partition by issuing n and following the same steps. Choose defaults for the partition type, partition number, first sector, and use +990M for the last sector. To write out the partition table type w.

Don’t ignore the warning here. You’ve changed the partition table of a disk but the kernel is still referencing the old (i.e., non-existent) partition table. Run partprobe and the kernel will reread all of its attached devices for the partition tables. If you run fdisk -l /dev/loop0 now, you won’t get a nasty comment about no partition table!

Okay, we have our partition table written, but there are no actual filesystems present. We will have to make them with mkfs (make filesystem) utilities. Using kpartx once more we need to map the partitions.

We’ll start with our first partition and create an ext4 filesystem, followed by a btrfs filesystem on the second partition.

Note: If mkfs.btrfs is not available you can install it with apt-get install btrfs-tools.

After these commands you should be able to use file -SL to examine the filesystems present.

Now let’s mount our two filesystems:

If you look in the ext4 directory you should find a directory called lost+found. This is a special directory present on ext-based filesystems where fsck puts recovered files. You will not see this directory present in the btrfs directory.

We’re going to unpack the Linux source tree into both filesystems. Download the source from Kernel.org. We are using 4.2 Release Candidate 5.

Using df in the respective directory you can see how much space was taken up.

Now that the source has been exploded into the two filesystems, unmount the partitions.

Go ahead and instruct kpartx to unmap the partitions as well and remind yourself that /dev/loop0 is still presenting our original image file. You can release it as well.

Writing Out the .img File

Now we come to writing the entire linuxsource.img out to a USB thumbdrive. Once more we will be using dd and once more we’ll warn you: ensure you are writing out to the USB device. Writing to the wrong device could render your system inoperable and destroy data!. I suggest watching /var/log/syslog with tail -f to see where the USB drive was attached. In this case it was attached to /dev/sdh.

Warning: Replace /dev/sdX below with the device your system mounted the USB drive.

dd will happily write out every byte in linuxsource.img onto the device presented at /dev/sdh. Once it is done we’re going to have a USB stick with a partition table and two partitions. Once the command completes run fdisk -l /dev/sdX, where X is where your system has the USB drive available.

We can take a look at our partitions and see our filesystems are there!

Mount a partition and verify that our Linux kernel source is intact!

Closing Remarks

Linux provides a variety of powerful tools for creating and manipulating disk images and disks. Although a little daunting at first the concepts of devices, partitions, and filesystems are quite simple to grasp. Hopefully this tutorial was helpful in exploring how to leverage these tools to create your own disk images!

1 thought on “Exploring .img Files on Linux”

Leave a Reply

Your email address will not be published. Required fields are marked *