Linux - how to format multiple file systems within one file?

9

1

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.

psihodelia

Posted 2011-12-12T16:18:13.983

Reputation: 747

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 – 2011-12-12T16:32:08.920

@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 – 2011-12-12T16:33:54.493

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 – 2011-12-12T16:51:58.333

Forgive me if I'm being naive here, but why not just use two separate files? – Garrett – 2011-12-12T16:54:29.250

Answers

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.

pjc50

Posted 2011-12-12T16:18:13.983

Reputation: 5 786

1

@MikkoRantalainen exactly. Here is a minimal runnable example: https://superuser.com/a/1367534/128124

– Ciro Santilli 新疆改造中心法轮功六四事件 – 2018-10-17T08:45:17.320

However, a drawback of this solution is requirement of superuser rights. – psihodelia – 2011-12-12T17:27:39.130

1I 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 – 2011-12-13T16:19:43.663

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 – 2013-01-16T08:28:24.820

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:

Shawn Chin

Posted 2011-12-12T16:18:13.983

Reputation: 1 174

Well, it doesn't work :( – psihodelia – 2011-12-12T17:28:19.363

@psihodelia It should. What's the result if you do this? – Daniel Beck – 2011-12-12T17:30:39.007

How does it not work? Do you get an error? Which step fails? – Shawn Chin – 2011-12-12T17:31:06.277

$ 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 – 2011-12-12T17:32:47.610

Please see updated original post with my solution. – psihodelia – 2011-12-12T17:34:00.590

1Might 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 – 2011-12-12T17:36:27.827

@psihodelia glad you found a solution. As you mentioned, that is simpler. – Shawn Chin – 2011-12-12T17:37:41.460

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.

Ciro Santilli 新疆改造中心法轮功六四事件

Posted 2011-12-12T16:18:13.983

Reputation: 5 621

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.

karatedog

Posted 2011-12-12T16:18:13.983

Reputation: 809

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 – 2011-12-12T17:30:37.957

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 – 2011-12-12T22:43:54.487