Linux - how to format multiple file systems within one file?
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.
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.
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:
- http://wiki.osdev.org/Loopback_Device#Mounting
- http://web2.clarkson.edu/projects/itl/honeypot/ddtutorial.txt
- http://wiki.eeeuser.com/howtocustomrestoreimage:pt2mkcustomimage
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.
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:
-
sfdisk
: deals with the partition table: How to create and format a partition using a bash script? -
mke2fs
: deals with EXT formatting of partitions: How to create ext2 image without superuser rights?
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.