How to create a multi partition SD disk image without root privileges? How to create a multi partition SD disk image without root privileges? linux linux

How to create a multi partition SD disk image without root privileges?


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: How to mount one partition from an image file that contains multiple partitions on Linux?

For more details, see:

The example:

#!/usr/bin/env bash# Input params.root_dir_1=root1root_dir_2=root2partition_file_1=part1.ext2partition_file_2=part2.ext2partition_size_1_megs=32partition_size_2_megs=32img_file=img.imgblock_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 topart_table_offset=$((2**20))cur_offset=0bs=1024dd 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#39675265loop-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.


I'm trying to do the same thing. My first attempt used the loopback block device, but I have found work-arounds to both steps that require loopback.

Steps with loopback

Here's what I'm doing ( $1 is image file name, $2 is file size):

  1. create zeroed disk image file with dd if=/dev/zero of=$1 bs=512 count=$(($2/512))
  2. create partition table with parted -s $1 mklabel msdos
  3. create partition with parted -s $1 "mkpart primary 0% 100%"
  4. attach partition to loop sudo losetup --find $1 --offset $OFFSET_TO_PARTITION_BYTES
  5. make file system with mkfs.ext4 with mkfs.ext4 -I 128 -L BOOT -b 2048 -O ^has_journal /dev/loop0 $SIZE_IN_2048_BLOCKS
  6. mount /dev/loop0

The loopback is used because

  • in step 4 & 5, mkfs doesn't have an offset option so losetup is used to solve that problem
  • in step 6, mount allows the use of the operating systems ext4 driver

Looback workarounds

Shitty work-around for step 4 & 5:

  • xmount --in dd --out vdi disk.img mnt/
  • vdfuse -f mnt/disk.vdi -r ./mnt2
  • ./mnt2 will now have two files: EntireDisk, and Partition1
  • point mkfs.ext4 at ./mnt2/Partition1

Work-around solution to step 6:

  • follow all steps for step 5 work around
  • use fuseext2 to mount ./mnt2/Partition1

Caveat

Caveat: ext4 support is not advertised in their documentation, and attempts to mount come with a warning:

This is experimental code, opening rw a real file system could bedangerous for your data. Please add "-o ro" if you want to open the filesystem image in read-only mode, or "-o rw+" if you accept the risk to testthis module

Update

vdfuse should be able to mount a raw image without the help of xmount, but there is a bug which ignores the RAW option.

I tracked down and fixed the bug with a patch here:

https://bugs.launchpad.net/ubuntu/+source/virtualbox-ose/+bug/1019075


you might want to look atgenextfs, that creates an ext2 filesystem in a regular file without any sort of mounting.