diary @ telent

Arms length#

Thu 23 Nov 2023 08:06:00 PM UTC

Topics: liminix

Since the last update I have added UBIFS for the Belkin RT3200 (and other devices with larger flash chips), and started an Arm 32 bit port which runs on QEMU and boots (though doesn't yet do much after booting) on the Turris Omnia. But then I got a little bit sidetracked into improving (read: replacing) the story for upgrading a router once it has Liminix running. (Blatting a new image onto the flash while the system is running from that same flash device is not a good idea. The best case scenario is that the flash write succeeds and then the system wedges solid, but I can't see any guarantee it wouldn't crash earlier)

Why is this important? (Why is this important now?) For squashfs systems (which can't be written to at all after imaging), and jffs2 (which can be written to somewhat, but with caveats) we'd rather not take the case apart and stick serial wires on it every time we re-image.

For UBIFS systems we usually have more space to play with, so we can expect to be able to do nixpkgs major version updates in place - but if the end-user does want to reinstall for any reason then we'd like to preserve the erase counters, which a simple flashcp (the moral equivalent of dd but for flash chips) won't do.

We do already have something that should address this: the kexecboot output creates an image almost just like the running system, but with the fillip that instead of booting with u-boot and running from flash, it boots from a running Linux system and runs from an emulated flash device that's actually just a contiguous section of physical RAM. But ...

So I had a new idea. Instead of rebooting into the new system in order to write the new system to flash, we can switch root of a running system to use a ram-based filesystem, and then it will be safe to do anything we want to the flash.

I've called it levitate because it allows you to hover above the filesystem without setting foot on it. The essence of it is you just add the package to your profile

  defaultProfile.packages =
    with pkgs; [
	  tcpdump
	  strace
	  (levitate.override { services = {
	    inherit (config.services) dhcpc sshd;
	   }; }
	  )
    ];

then you can login and run levitate to populate the maintenance mode filesystem and reboot to exec into it. The UI is still a bit WIP and there's no documentation yet, but I'm quite pleased with it so far.