Me: I couldn't write anything longer than 20 lines in make - there's just one type (string), no debugger, no data structures, no standard library, and not even modules.
Buildroot developers: let's write a build system in make!
Coincidentally I tried this recently. I dunno if I liked it. It uses the kernel's `make menuconfig` system which seems like it occupies a bad place between "easy usable GUI" and "robust config file you can check in to git".
Once you've configured it it then does a lot of downloading and compilation of random stuff and it's all strung together with janky shell scripts which means it's almost guaranteed to break.
I got some weird errors that returned zero google results and the source of the error was a long awful shell pipeline involving `sed`, `tr` etc.
Doesn't scream quality.
I gave up and switched to manually compiling Linux and OpenSBI (which is really all I needed so buildroot was overkill anyway). Went much smoother and I actually vaguely understood what was happening.
I haven't tried Yocto, maybe that is better engineered.
I've previously developed a commercial product that used buildroot.
In that case, it used an A/B partition layout like Android, along with a custom update script and kernel-based bootloader to implement atomic updates and fallback capability. The rootfs image was built by buildroot and devices would query an API and download the image, then write it to the inactive root partition.
You can do effectively the same thing with GRUB, but the project I worked on also supported devices that booted using u-boot. The kexec bootloader allowed a single implementation for different architectures and platforms.
So, the answer is you can update however you want, but there are a few common ways it's done in embedded.
Rather than using a custom update script something like swupdate is probably a better option which is well supported in buildroot and can do A/B dual-copy in addition to other layouts.
Is there a common way with Buildroot and A/B partitioning to make it so that if the reboot into the updated partition fails to boot, it will reboot into the old partition?
For example, if the new partition is corrupt, or if there is a software bug that causes one of the following to happen:
- the partition is unbootable, or
- the device is able to begin the boot, even starting to run the new kernel, but somewhere along the way it locks up. Whether that be a kernel panic early on, or later on when systemd has started but one or more important services fail to start, or
- The device finishes the initial boot successfully, including all of the services managed by systemd, but after say a few minutes, some services are exhibiting unstable behavior (like services crashing and starting and crashing and starting), or the kernel panics after everything had been up and running for a while
Use the hardware watchdog timer. When the machine resets, the bootloader can check a hardware register to determine the reset cause, and then boot into a different OS partition.
(note: not every SoC has a register indicating reset cause, I’ve worked with Allwinner chips that don’t, so alternate methods may be required)
Enable the watchdog timer at the start of the bootloader. (I work with arm systems so this would be in uboot). If no bootable OS is found, or the system crashes before the kernel fully boots, the watchdog times out.
In Linux, enable the watchdog timer at boot in your kconfig. Then have a userspace service that periodically pings /dev/watchdog to keep the system alive. Have your panic handler just hang, and the watchdog will reset the machine.
Another helpful trick to save panic logs is to use pstore/ramoops to keep a portion of the kernel logs across resets, and then save the pstore buffer out to disk after booting into the recovery system.
Well, buildroot is mainly for embedded applications, so whatever applies to that: OTA updates with A/B partitioning are common. OStree-based are getting a lot of traction as well.
But technically you could build something with a package manager etc and update as usual. It's just a build system.
I would love to know. I currently have an embedded product using buildroot and as it is not exposed to a network at all, I don't have any worries about security. However, I'd love to hear of a nice mechanism to basically upgrade the system image in place. I imagine you could use something like a pair of partitions and just change the kernel boot parameters to point at the most recent one, but I'm curious about what solutions people use.
I work on the Nerves project which does Elixir on top of Buildroot and there we use fwup (https://github.com/fwup-home/fwup) which does a very nice job of a lot of this. Including signing, hashing and more.
It's sort of out of the scope of Buildroot, but there are different systems like mender or swupdate that cover updates. They tend to need some level of platform specific changes because embedded systems these days have 7 levels of bootloaders.
I’ve been using fwup (https://github.com/fwup-home/fwup) in embedded Linux consumer products for almost 10 years and it has Just Worked.
Supports A/B updates, uboot integration, and signed update files.
Not sure about buildroot, but in Yocto it’s fairly straightforward to write an image creation recipe that bundles your ext4 filesystem image(s) into an update file you can deploy.
We’ve built something that goes well with buildroot for installing and updating apps during development or in production.
Does not require cloud or internet access.
https://www.voyonic-systems.de/products/voyonic-fieldkit
Me: I couldn't write anything longer than 20 lines in make - there's just one type (string), no debugger, no data structures, no standard library, and not even modules.
Buildroot developers: let's write a build system in make!
I wonder if one day we'll see Zig used for system development. Among its other peculiarities, it also use itself as build language.
https://ziglang.org/learn/build-system/
Coincidentally I tried this recently. I dunno if I liked it. It uses the kernel's `make menuconfig` system which seems like it occupies a bad place between "easy usable GUI" and "robust config file you can check in to git".
Once you've configured it it then does a lot of downloading and compilation of random stuff and it's all strung together with janky shell scripts which means it's almost guaranteed to break.
I got some weird errors that returned zero google results and the source of the error was a long awful shell pipeline involving `sed`, `tr` etc.
Doesn't scream quality.
I gave up and switched to manually compiling Linux and OpenSBI (which is really all I needed so buildroot was overkill anyway). Went much smoother and I actually vaguely understood what was happening.
I haven't tried Yocto, maybe that is better engineered.
How are kernel or application updates applied to buildroot-installed systems?
I've previously developed a commercial product that used buildroot.
In that case, it used an A/B partition layout like Android, along with a custom update script and kernel-based bootloader to implement atomic updates and fallback capability. The rootfs image was built by buildroot and devices would query an API and download the image, then write it to the inactive root partition.
You can do effectively the same thing with GRUB, but the project I worked on also supported devices that booted using u-boot. The kexec bootloader allowed a single implementation for different architectures and platforms.
So, the answer is you can update however you want, but there are a few common ways it's done in embedded.
Rather than using a custom update script something like swupdate is probably a better option which is well supported in buildroot and can do A/B dual-copy in addition to other layouts.
https://sbabic.github.io/swupdate/scenarios.html
Is there a common way with Buildroot and A/B partitioning to make it so that if the reboot into the updated partition fails to boot, it will reboot into the old partition?
For example, if the new partition is corrupt, or if there is a software bug that causes one of the following to happen:
- the partition is unbootable, or
- the device is able to begin the boot, even starting to run the new kernel, but somewhere along the way it locks up. Whether that be a kernel panic early on, or later on when systemd has started but one or more important services fail to start, or
- The device finishes the initial boot successfully, including all of the services managed by systemd, but after say a few minutes, some services are exhibiting unstable behavior (like services crashing and starting and crashing and starting), or the kernel panics after everything had been up and running for a while
Use the hardware watchdog timer. When the machine resets, the bootloader can check a hardware register to determine the reset cause, and then boot into a different OS partition.
(note: not every SoC has a register indicating reset cause, I’ve worked with Allwinner chips that don’t, so alternate methods may be required)
Enable the watchdog timer at the start of the bootloader. (I work with arm systems so this would be in uboot). If no bootable OS is found, or the system crashes before the kernel fully boots, the watchdog times out.
In Linux, enable the watchdog timer at boot in your kconfig. Then have a userspace service that periodically pings /dev/watchdog to keep the system alive. Have your panic handler just hang, and the watchdog will reset the machine.
Another helpful trick to save panic logs is to use pstore/ramoops to keep a portion of the kernel logs across resets, and then save the pstore buffer out to disk after booting into the recovery system.
For systems using U-Boot you can use the bootcount[1] feature to detect the failure and react by booting into the old environment.
Edit: This doesn't cover your running instability case, but that seems more like a feature that should be implemented using a user space watchdog.
[1] https://docs.u-boot.org/en/latest/api/bootcount.html
There's a very useful framework called greenboot[0] for the latter case.
[0] https://github.com/fedora-iot/greenboot
Many embedded systems use SWupdate to manage this, which can hook into uboot.
Well, buildroot is mainly for embedded applications, so whatever applies to that: OTA updates with A/B partitioning are common. OStree-based are getting a lot of traction as well.
But technically you could build something with a package manager etc and update as usual. It's just a build system.
I would love to know. I currently have an embedded product using buildroot and as it is not exposed to a network at all, I don't have any worries about security. However, I'd love to hear of a nice mechanism to basically upgrade the system image in place. I imagine you could use something like a pair of partitions and just change the kernel boot parameters to point at the most recent one, but I'm curious about what solutions people use.
That's the general wisdom I've seen.
I work on the Nerves project which does Elixir on top of Buildroot and there we use fwup (https://github.com/fwup-home/fwup) which does a very nice job of a lot of this. Including signing, hashing and more.
This is a real example of a config: https://github.com/nerves-project/nerves_system_rpi4/blob/ma...
I use swupdate myself with buildroot.
https://sbabic.github.io/swupdate/swupdate.html
It's sort of out of the scope of Buildroot, but there are different systems like mender or swupdate that cover updates. They tend to need some level of platform specific changes because embedded systems these days have 7 levels of bootloaders.
I’ve been using fwup (https://github.com/fwup-home/fwup) in embedded Linux consumer products for almost 10 years and it has Just Worked.
Supports A/B updates, uboot integration, and signed update files.
Not sure about buildroot, but in Yocto it’s fairly straightforward to write an image creation recipe that bundles your ext4 filesystem image(s) into an update file you can deploy.
You build a new filesystem image and apply the new filesystem to the system.