Rugix with Buildroot
Rugix is a set of tools to build and deploy embedded Linux devices at scale. The suite includes an efficient and secure OTA update client. While Rugix has experimental support for Yocto, there is no official Buildroot integration yet. So we did just that.
The work targets the Raspberry PI 4, because:
- It’s supported by the Yocto integration as well.
- It’s a nice proof of concept target, because it’s cheap and widely available.
- We had it laying in the drawer.
The first step was to understand how the whole system works. So we read some code and confirmed our findings by building and booting a Yocto image. The system uses the tryboot feature from the Raspberry PI EEPROM bootloader. This allows defining a main and alternate slot inside config.ini to implement A-B partition schemes. You can even put the Raspberry PI firmware on A-B partitions to make it part of your updates. To install an update, you simply install the new version into the unused partitions and reboot with a special flag which tells the bootloader to temporarily boot into the alternate slot. If that succeeded you can atomically replace the config.txt which defines the main slot using filesystem operations.
Rugix implements all of that in the rugix-ctrl tool. It’ll even mount the correct partitions for you if you make it load before your init system using the init kernel command line option. Image bundles which can be installed using rugix-ctrl can be created using rugix-bundler. So all we had to do was to add Buildroot packages for these two tools and configure the Rasberry PI 4 board for tryboot.
For that, we modified the partition table in the genimage config to look like this:
tryboot: contains the tryboot config.txtboot_a,boot_b: The Raspberry PI config partitions (firmware, cmdline, kernel, …) corresponding to a boot slot.rootfs_a,rootfs_b: The rootfs of the respective boot slot.persistent: Since the rootfs is mounted read-only, this serves as an overlay. This is required in the default configuration of Rugix.
To tie Rugix into the build system, we wrote a rugix-bundle.toml and modified post-image.sh to create images from the modified genimage config and create an update bundle using rugix-bundler.
Creating Buildroot packages for rugix-bundler and rugix-ctrl was also mostly straight forward, but required a couple fixes:
- Ignore
rustfmtnot being available, so we don’t have to install that just for formatting generated code. - Use symlinks instead of relative paths into parent directories to make
cargo publishwork. This is needed because Buildroot automatically vendors Rust dependencies. - Fix building on 32bit platforms. Our fixes are partly workarounds, so these could use some more work.
The only runtime fix we needed, was to make rugix-ctrl mount devtmpfs before running the init system. That’s usually done by the kernel, but since Rugix sets up a chroot, that mount was missing. Systemd can handle that and just mounts it itself if it’s missing, but the Busybox init system would need fstab changes for that.
And that’s it. We tested that it boots and successfully did an update via a local file. So far, it works great.
The code can be found on Github.





