The official Raspian stretch image is provided as an img file with a DOS/MBR boot sector and 2 partitions, a boot partition
/bootand the rootfs mounted at
We can create a script which allows switching between the filesystem which is mounted at
/and an alternative recovery root partion and provide tools on the recovery partition to reset the main root partition back to factory state.
And we can do the reset over ssh which makes it super easy to automate configuration on the Pi!
This article is a follow up to the previous article and explains the details on how to create a factory restore partition for a raspberry pi. Checkout the repo from here to get the files.
Once a Pi is booted with this modified image, it has 3 partitions rather than 2,
and has a
/boot/factory_reset command which will trigger a factory reset. For
example if you login to the Pi with the modified recovery image and issue the
The Pi will reset itself…
And if you wait 10 minutes or so… It will replace the
/ file system with a
pristine copy of raspbian (and enabled ssh access at the same time), and you will
be able to login again to fresh Raspberry Pi over ssh;
Offical Raspian Images
The official raspian stretch lite image is about 1.7GB and contains 2 partitions.
/boot partition containing the kernal and other stuff, and the
which contains the OS.
You can see that information using the
/boot/cmdline.txt on the Pi contains the boot information with parameters
init script and the
root partition to boot from;
Working around the Init root partition resizer
The init script /usr/lib/raspi-config/init_resize.sh is run on the first boot, and resizes the last partition to fill the sdcard. In order to work with the resizer script, the idea is to add the recovery partition after the boot partition and before the main rootfs.
If we were to add the recovery partition at the end, the init resizer script
would expand the recovery partition to fill the disk, rather than the live
So basically we want to insert the recovery partition here…
root= rootfs or recovery partition on boot
root= option in
/boot/cmdline.txt selects the root filesystem which is
then mounted and booted into the OS.
By default that points at the vanilla root. If we add another partition, this value needs updating. It also needs changing in order to boot from the recovery partition.
While coming up with this script I had some issues that I could not get the Pi to use the disk UUID to boot, it would only work with the PARTUUID. However the resizer.sh script resets the PARTUUID during its resizing process which complicates matters.
Generating UUID and PARTUUID for the disks
As we are going to be cloning a disk, we have a problem of a duplicate UUID for that disk. We also need to have a PARTUUID for the cmdline.txt file. So we generate random values for this as a first step;
Creating a blank disk
img file to work with;
This is the image that will be written to the sdcard. This is a way to initialize
img file of a specific size. In this case
2000 x 4M. Currently that is
fixed, but I would like to inspect those values from the source image as a future
This creates an empty file with zeros. We need to add a partition table to that;
These values are hard coded to fit the raspian stretch lite image, and it’s on the TODO list to inspect the sizes from the source image file.
We can inspect what was created using the follwing command
We need to make some changes to the paritions in the image, and copy the filesystems from the source image, so we mount them on the loopback device using the following commands;
Now the partitions from the img file are available as loopback devices so we can work with them;
The next step is to mount the source image on loopback device similar to the previous step
Now we can copy the partitions from the source image to the recovery image;
We now write the UUIDs for the disks so they are unique going forward;
The next thing is that the recovery partition is 4G from the
above, but the filesystem that we just wrote is only
1.7 GB. So we need to
resize that filesystem;
We can now mount those partions and make the changes for factory reset;
The first thing is that we want the Pi to boot off the 3rd partition, rather
than the 2nd, do we need to modify
/boot/cmdline.txt in the restore image;
(and also enable ssh…)
The next thing is to make backup of the
cmdline.txt so we can put it back after
So the next step we create a
/boot/cmdline.txt which is used during recovery.
However as the PARTUUID is reset during resizing. we include a token
which is replaced at runtime by our own script, and we tell the Pi to boot our
recovery script when its reset
(there is probably a
simpler way to do this) But I couldn’t get
type booting to work. So I seem to be stuck with manipulating the
The next step is to write out the script that actually resets the pi. This is on the recovery partition root fs.
We also need to copy the recovery image (
/opt/recovery.img) to the restore partition, but we do that
last because we want the modifications we are making to be persistent after
Note that it also enables ssh for the restored OS.
we also need a command which triggers the recovery from the live system;
Notice that this inspects the blkid of the PARTUUID, and replaces the token
XXXYYYXXX) created earlier with the correct runtime PARTUUID
In addition we need to update the
/etc/fstab on each of the root partitions
so they correct mount their respective partitions;
Note: using UUID seems to work fine in OS land, but not in cmdline.txt… weird huh
Write out the rootfs image to a fisk image on the recovery partition so it can be restored. @TODO zip this…
Finally, unmount the filesystems and loop devices;
Use the following command to write the image to an sdcard;
2018-03-13-raspbian-stretch-lite.restore.img now contains
- boot partition pointing at partition 3
- recovery script at
- Recovery partition at partition 2
- Recovery image in
/opt/recovery.imgof recovery partition
/etc/fstabfor partition 2 and 3
- reset script at
/usr/lib/raspi-config/init_resize2.shof recovery partition
So write the img to a file system, and when you want to reset it, issue the following command;
Make a cup of coffee, and wait 10 minutes, and by the time your are back, the Pi will be fresh and new and ready and waiting…