8

I need to create a disk image with two empty file systems. I have created it using

dd if=/dev/zero of=./disk.img bs=1MiB count=1024

Next, I have created 2 primary partitions using fdisk disk.img; one is FAT32 and other is EXT3. Now, I have to format both partitions in order to create file-systems to be mounted as -o loop devices. But I can't understand how to format them? I can't use mkfs.vfat on disk.img. So I am totally confused.

SOLUTION: Thanks to answer from @pjc50 I found very simple solution:

sudo aptitude install multipath-tools
sudo kpartx -a disk.img   #it maps (mounts) found partitions to /dev/mapper/loop...
sudo mkfs.vfat -F 32 -n boot /dev/mapper/loop0p1
sudo mkfs.ext3 -L rootfs /dev/mapper/loop0p2

A drawback of this solution is requirement of superuser rights.

  • I doubt that all those programs will be able to use partitions inside a file. Can you create the two filesystems in separate files and then merge them in a big file with dd? – golimar Dec 12 '11 at 16:32
  • @golimar: but I will need MBR on such drive, I don't know how it's possible to merge different filesystems created separately as distinct files – psihodelia Dec 12 '11 at 16:33
  • You can use the MBR of the original file you said. dd allows offsets with the 'size' and 'skip' commands. You would need to find the exacts offsets and then overwrite part of the big file with the two smaller ones – golimar Dec 12 '11 at 16:51
  • Forgive me if I'm being naive here, but why not just use two separate files? – Garrett Dec 12 '11 at 16:54
9

It appears you can use the kpartx tools: http://robert.penz.name/73/kpartx-a-tool-for-mounting-partitions-within-an-image-file/

Kpartx can be used to set up device mappings for the partitions of any partitioned block device. It is part of the Linux multipath-tools. With kpartx -l imagefile you get an overview of the partitions in the image file and with kpartx -a imagefile the partitions will accessible via /dev/mapper/loop0pX (X is the number of the partition). You can mount it now with mount /dev/mapper/loop0pX /mnt/ -o loop,ro. After unmounting you can disconnect the mapper devices with kpartx -d imagefile.
  • However, a drawback of this solution is requirement of superuser rights. – psihodelia Dec 12 '11 at 17:27
  • 1
    I doubt a solution exists that doesn't require superuser rights! That is, this is the sort of operation I don't expect normal users to be able to do without a specific mechanism set up by the super user in advance (eg through sudo) – pjc50 Dec 13 '11 at 16:19
  • 2
    @pjc50: it's possible to do this without superuser rights: one must first create each partition as a separate file, then manually create the disk image and copy the partitions to the disk image after creating partition table to the disk image. – Mikko Rantalainen Jan 16 '13 at 8:28
  • 1
    @MikkoRantalainen exactly. Here is a minimal runnable example: superuser.com/a/1367534/128124 – Ciro Santilli 新疆改造中心996ICU六四事件 Oct 17 '18 at 8:45
7

You can do so by first mounting your partitions to /dev/loop? using losetup with the -o option to specify a suitable offset to your partition. The offset can be calculated based on the output of fdisk -l disk.img (start_sector * sector_size).

For example:

losetup -o32256 /dev/loop1 ./disk.img   # mount first partition

Once mounted, you can then proceed to format the partition using mkfs.*:

mkfs.vfat -F32 /dev/loop1

For more details and examples, see the following articles:

  • Well, it doesn't work :( – psihodelia Dec 12 '11 at 17:28
  • @psihodelia It should. What's the result if you do this? – Daniel Beck Dec 12 '11 at 17:30
  • How does it not work? Do you get an error? Which step fails? – Shawn Chin Dec 12 '11 at 17:31
  • $ sudo mkfs.vfat -F32 /dev/loop1 mkfs.vfat 3.0.9 (31 Jan 2010) Loop device does not match a floppy size, using default hd params – psihodelia Dec 12 '11 at 17:32
  • 1
    Might help if you specify the block size when calling mkfs.vfat. See first link I provided. Also mentioned in the article, the floppy warning is expected and can be ignored – Shawn Chin Dec 12 '11 at 17:36
1

I would go with the tools I have in mind:

  • create a new VM in Virtualbox with one disk, that would usually be /dev/sda
  • boot into the VM with a GParted Live CD
  • partition and format the disk in the VM to your needs (2 partitions, different file systems, etc.)
  • then use dd to export /dev/sda to a file

With an educated guess it would take about 15 minutes.

  • Smart tricky solution :) But I don't believe it takes less than 15 Minutes. By the way, it's hard to automate it, because it requires a user in a graphic interface (so, no scripting is possible = not a Unix way). – psihodelia Dec 12 '11 at 17:30
  • It doesn't take long :-) because the virtual disk is small, and no OS installation is done. The longest part is the GParted boot time. – karatedog Dec 12 '11 at 22:43
1

Minimal runnable sfdisk + mke2fs example without sudo

In this example, we will create, without sudo or setsuid, an image file that contains two ext2 partitions, each populated with files from a host directory.

We will then use sudo losetup just to mount the partitions to test that the Linux kernel can actually read them as explained at: https://stackoverflow.com/questions/1419489/how-to-mount-one-partition-from-an-image-file-that-contains-multiple-partitions/39675265#39675265

For more details, see:

The example:

#!/usr/bin/env bash

# Input params.
root_dir_1=root1
root_dir_2=root2
partition_file_1=part1.ext2
partition_file_2=part2.ext2
partition_size_1_megs=32
partition_size_2_megs=32
img_file=img.img
block_size=512

# Calculated params.
mega="$(echo '2^20' | bc)"
partition_size_1=$(($partition_size_1_megs * $mega))
partition_size_2=$(($partition_size_2_megs * $mega))

# Create a test directory to convert to ext2.
mkdir -p "$root_dir_1"
echo content-1 > "${root_dir_1}/file-1"
mkdir -p "$root_dir_2"
echo content-2 > "${root_dir_2}/file-2"

# Create the 2 raw ext2 images.
rm -f "$partition_file_1"
mke2fs \
  -d "$root_dir_1" \
  -r 1 \
  -N 0 \
  -m 5 \
  -L '' \
  -O ^64bit \
  "$partition_file_1" \
  "${partition_size_1_megs}M" \
;
rm -f "$partition_file_2"
mke2fs \
  -d "$root_dir_2" \
  -r 1 \
  -N 0 \
  -m 5 \
  -L '' \
  -O ^64bit \
  "$partition_file_2" \
  "${partition_size_2_megs}M" \
;

# Default offset according to
part_table_offset=$((2**20))
cur_offset=0
bs=1024
dd if=/dev/zero of="$img_file" bs="$bs" count=$((($part_table_offset + $partition_size_1 + $partition_size_2)/$bs)) skip="$(($cur_offset/$bs))"
printf "
type=83, size=$(($partition_size_1/$block_size))
type=83, size=$(($partition_size_2/$block_size))
" | sfdisk "$img_file"
cur_offset=$(($cur_offset + $part_table_offset))
# TODO: can we prevent this and use mke2fs directly on the image at an offset?
# Tried -E offset= but could not get it to work.
dd if="$partition_file_1" of="$img_file" bs="$bs" seek="$(($cur_offset/$bs))"
cur_offset=$(($cur_offset + $partition_size_1))
rm "$partition_file_1"
dd if="$partition_file_2" of="$img_file" bs="$bs" seek="$(($cur_offset/$bs))"
cur_offset=$(($cur_offset + $partition_size_2))
rm "$partition_file_2"

# Test the ext2 by mounting it with sudo.
# sudo is only used for testing, the image is completely ready at this point.

# losetup automation functions from:
# https://stackoverflow.com/questions/1419489/how-to-mount-one-partition-from-an-image-file-that-contains-multiple-partitions/39675265#39675265
loop-mount-partitions() (
  set -e
  img="$1"
  dev="$(sudo losetup --show -f -P "$img")"
  echo "$dev" | sed -E 's/.*[^[:digit:]]([[:digit:]]+$)/\1/g'
  for part in "${dev}p"*; do
    if [ "$part" = "${dev}p*" ]; then
      # Single partition image.
      part="${dev}"
    fi
    dst="/mnt/$(basename "$part")"
    echo "$dst" 1>&2
    sudo mkdir -p "$dst"
    sudo mount "$part" "$dst"
  done
)
loop-unmount-partitions() (
  set -e
  for loop_id in "$@"; do
    dev="/dev/loop${loop_id}"
    for part in "${dev}p"*; do
      if [ "$part" = "${dev}p*" ]; then
        part="${dev}"
      fi
      dst="/mnt/$(basename "$part")"
      sudo umount "$dst"
    done
    sudo losetup -d "$dev"
  done
)

loop_id="$(loop-mount-partitions "$img_file")"
sudo cmp /mnt/loop0p1/file-1 "${root_dir_1}/file-1"
sudo cmp /mnt/loop0p2/file-2 "${root_dir_2}/file-2"
loop-unmount-partitions "$loop_id"

Tested on Ubuntu 18.04. GitHub upstream.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.