It is possible to create an empty image for a Raspberry Pi. Then you can copy an operating system with a boot and root partition to it and boot. To fill the empty image you can use any usable file copy method, e.g. from a tar archive, or rsync, or just cp. This way you are completely free to shrink or expand storage, or use other partition sizes than given by the original images. You can do all of it on a linux laptop, no need to use a Raspberry Pi. If you have made the image you can flash it to an SD Card and boot it in a RasPi. I have tested it by copying Raspbian Stretch Lite, Raspbian Buster Lite and Raspbian Buster with Desktop to a modified partition scheme and boot it up.
Create an empty image file
We just create a file with Null bytes of the size we want, partition it and format the partitions in the file. I will use an image with 3.9 GiB (3900 MiB) to be used with Raspbian Buster with Desktop.
This gives the empty file:
laptop ~$ sudo -Es
laptop ~# dd of=raspbian.img seek=3900M bs=1 count=0
Create a default msdos partition table on the virgin image and partition it for a fat32 boot partition and an ext4 root partition:
laptop ~# parted raspbian.img mktable msdos
laptop ~# parted raspbian.img mkpart primary fat32 2048s 257MiB
laptop ~# parted raspbian.img mkpart primary ext4 257MiB 100%
Now we have to format the partitions with a file system but there is a problem. The formating programs need a block device file from directory /dev
. Fortunately we can use loop devices to address the partitions as block devices. We will use losetup
to do it:
laptop ~# losetup --find --partscan --show raspbian.img
laptop ~# ls /dev/loop0*
/dev/loop0 /dev/loop0p1 /dev/loop0p2
# format partitions
laptop ~# mkfs.vfat -F 32 -n BOOT /dev/loop0p1
laptop ~# mkfs.ext4 -L rootfs /dev/loop0p2
Now we have a formated but empty image to which we can copy an operating system.
Copy an operating system to the empty image file
For example I will use a SD Card attached to /dev/sdb
. Its content will be copied to the image, provided it all fits to the new image file. I will mount the SD Card and copy the data:
# mount the SD Card
laptop ~# mkdir /mnt/sdcp2
laptop ~# mount /dev/sdb2 /mnt/sdcp2/
laptop ~# mount /dev/sdb1 /mnt/sdcp2/boot
The image partitions are still attached from the first step. Now we will mount them:
# mount the image partitions
laptop ~# mkdir /mnt/imgp2
laptop ~# mount /dev/loop0p2 /mnt/imgp2/
laptop ~# mkdir /mnt/imgp2/boot
laptop ~# mount /dev/loop0p1 /mnt/imgp2/boot
# copy the SD Card
laptop ~# cp -a /mnt/sdcp2/* /mnt/imgp2/
If you coppied Raspbian then change device name for root partition in boot/cmdline.txt
and in etc/fstab
to /dev/mmcblk0p1 and /dev/mmcblk0p2 because the used PARTUUID there isn't valid anymore. On other operating systems check, if they address the partitions the right way.
laptop ~# sed -i 's/root=PARTUUID=[a-z0-9]*-02/root=\/dev\/mmcblk0p2/' /mnt/imgp2/boot/cmdline.txt
laptop ~# sed -i 's/^PARTUUID=[a-z0-9]*-01/\/dev\/mmcblk0p1/' /mnt/imgp2/etc/fstab
laptop ~# sed -i 's/^PARTUUID=[a-z0-9]*-02/\/dev\/mmcblk0p2/' /mnt/imgp2/etc/fstab
# clean up
laptop ~# umount /mnt/sdcp2/boot
laptop ~# umount /mnt/sdcp2
laptop ~# rmdir /mnt/sdcp2
laptop ~# umount /mnt/imgp2/boot
laptop ~# umount /mnt/imgp2
laptop ~# rmdir /mnt/imgp2
laptop ~# losetup --detach-all
That's it. Flash raspbian.img to an SD Card and boot it in a RasPi.
Details
By default Raspbian uses PARTUUID
to address storage and partitions on it. But this is a problem because with a new image we also have new PARTUUID
. Then you have the problem that the installation does not boot. So we change the partition names to the more generic names /dev/mmcblk0p1
and /dev/mmcblk0p2
.
references:
[2] Is it possible to use partition UUID for root-parameter in cmdline.txt?