1

I want to make my own image file for a Raspberry Pi so I can copy any usable operating system to it and boot it. This way I'm also able to size down partitions or use other partition sizes.

Is it possible to create a new but empty image file and copy an operating system from other sources to it, for example from another SD Card, an available image or a tar archive?

2

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 and Raspbian Buster Lite 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 2.2 GB (2200 MB).

This gives the empty file:

laptop ~$ sudo -Es
laptop ~# dd of=raspbian.img seek=2200M 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 8192s 260MB
laptop ~# parted raspbian.img mkpart primary ext4 260MB 100%

Now we have made a master boot record (MBR), the very first sector with 512 bytes. It also contains a very small boot sequence at the beginning and the partition table at the end. You can check it with:

laptop ~# hd -v -n512 raspbian.img

But the boot sequence is not used by a Raspberry Pi so we will delete it with:

laptop ~# dd if=/dev/zero of=raspbian.img bs=1 count=440 conv=notrunc

Have an attention of the count=440. A greater number will also delete the partition table. Deleting the boot sequence is not really required but I do it to be on the save side because the MBR from the original Raspbian image is also nullified on this sequence.

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 but we have exactly to know where they are lying in the image file. We show it with parted and use the Start an Size for the loop devices. You will find the right numbers from the example:

laptop ~# parted raspbian.img unit s print free
Model:  (file)
Disk /home/ingo/devel/raspi/raspbian.img: 4505600s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number  Start    End       Size      Type     File system  Flags
        32s      8191s     8160s              Free Space
 1      8192s    507903s   499712s   primary               lba
 2      507904s  4505599s  3997696s  primary

# define loop devices
laptop ~# losetup /dev/loop1 raspbian.img --offset $((8192*512)) --sizelimit $((499712*512))
laptop ~# losetup /dev/loop2 raspbian.img --offset $((507904*512)) --sizelimit $((3997696*512))

# format partitions
laptop ~# mkfs.vfat -F 32 -n BOOT /dev/loop1
laptop ~# mkfs.ext4 -L rootfs /dev/loop2

# clean up
laptop ~# losetup -d /dev/loop1
laptop ~# losetup -d /dev/loop2

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. Here I use a SD Card with Raspbian Buster Lite. I will mount the SD Card and the image partitions 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

To mount the image partitions you will find the offsets with parted as shown in the example above.

# mount the image partitions
laptop ~# mkdir /mnt/imgp2
laptop ~# mount -o loop,offset=$((507904*512)),sizelimit=$((3997696*512)) raspbian.img /mnt/imgp2/
laptop ~# mkdir /mnt/imgp2/boot
laptop ~# mount -o loop,offset=$((8192*512)),sizelimit=$((499712*512)) raspbian.img /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. Check on other operating systems 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/imgp2/boot
laptop ~# umount /mnt/imgp2
laptop ~# rmdir /mnt/imgp2
laptop ~# umount /mnt/sdcp2/boot
laptop ~# umount /mnt/sdcp2
laptop ~# rmdir /mnt/sdcp2

That's it. Flash raspbian.img to an SD Card and boot it in a RasPi.

Details

Have in mind that we are working in units (sectors) of 512 bytes.

We have to address the beginning of the partitions in the image. This is done with an offset to the mount command. For details to do this look at (1).

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.


referencess:
[1] How can I mount a Raspberry Pi Linux distro image?
[2] Is it possible to use partition UUID for root-parameter in cmdline.txt?

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.