3

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?

Ingo
  • 40,606
  • 15
  • 76
  • 189

1 Answers1

7

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?

Ingo
  • 40,606
  • 15
  • 76
  • 189
  • Isn't `cp` bad for these kind of situations, as it doesn't preserve permissions? I know that `sync` is better with the archive switch. – Binar Web Dec 22 '20 at 09:13
  • @BinarWeb Do yo mean `rsync`? `sync` is for flashing buffers. I have checked that `cp` is doing it correct with option `-a, --archive, same as -dR --preserve=all`. No need to use overkilled `rsync`. – Ingo Dec 22 '20 at 19:34
  • Yes, I meant `rsync`. And I guess not reading a manual got me thinking it's not possible to do it with `cp`. Why is overkill to use `rsync`? I use it for backups. – Binar Web Dec 22 '20 at 19:56
  • @BinarWeb Discussion about `rsync` is off topic now. I like to keep things as light and simple as possible because its less error prone. `rsync` is mainly made to synchronize complete web sites over slow connections with verify and retry by only copy changed files. That it can also do what `cp` can do, is only a side effect of its powerful possibilities. – Ingo Dec 22 '20 at 20:48