commit 52967f746ba643dc38bc496beed492b2dd139a8f
parent 1ff779c1a91a8d5c01f3924085f0c66c2c683d9e
Author: dan <dan@telent.net>
Date: Tue, 24 Dec 2024 12:24:13 +0000
Merge branch 'main' into linux-version-with-openwrt
Diffstat:
38 files changed, 579 insertions(+), 255 deletions(-)
diff --git a/NEWS b/NEWS
@@ -132,4 +132,28 @@ and then run the generated `install.sh` script
result/install.sh root@192.168.8.1
+2024-12-16
+Config options changed: if you had set config.hardware.dts.includes
+(maybe in an out-of-tree device port) to specify the search paths
+in which dtc finds include files, you will need to change this to
+hardware.dts.includePaths.
+
+The "new" hardware.dts.includes option is now for dtsi files which
+should be merged into the device tree.
+
+2024-12-19
+
+Incremental updates changed again (but not massively). From hereon in,
+the preferred way to do an incremental update on an installed device
+with a writable filesystem is to build the updater output
+
+ nix-build -I liminix-config=hosts/myhost.nix --argstr deviceName turris-omnia -A outputs.updater
+
+and then run the generated `update.sh` script. See
+https://www.liminix.org/doc/admin.html#updating-an-installed-system
+
+2024-12-22
+
+outputs.zimage is now outputs.kernel.zImage. This is unlikely to
+affect many people at all but I mention it anyway.
+\ No newline at end of file
diff --git a/THOUGHTS.txt b/THOUGHTS.txt
@@ -6539,3 +6539,134 @@ using a Makefile
idea 2: when a configuration contains levitate, something similar
but necessarily more "manual" to do the analogous thing
+
+
+Sun Dec 15 18:55:55 GMT 2024
+
+Where we left off with this, rotuer was crashing randomly or failing
+to boot every time we tried to add log shipping, which is not very
+ideal. I started doing something with logging to /dev/pmsg0
+(CONFIG_PSTORE_PMSG) but I think (there seems not to be anything
+written down :-( ) that the gl-ar750 kernel needs it added to kconfig and device tree
+
+https://wiki.postmarketos.org/wiki/User:Knuxify/Enabling_pstore_and_ramoops
+
+we could add a new hardware.dts.dtsi = [] option so that any module
+could add a new chunk of dts. (Ideally we'd call it `includes`
+but that conflicts with the existing use of `includes` to specify
+search path. Maybe rename?)
+
+would we ever use it except in a hardware device definition?
+(Or user config?) I guess if we were consistent with names
+then we could set up nodes in the device file with status="disabled"
+and enable them in the module, except that dt doesn't consistently
+use status and in fact there isn't one for reserved-memory
+
+we could use global config to enable pstore_msg and check it in
+the device module to enable the needed hw support
+
+Tue Dec 17 23:39:28 GMT 2024
+
+I think we can just stick a tee in the fallback logger pipeline that
+writes to /dev/pmsg0
+
+Need to check it's a circular buffer
+
+do we want to do anything about recovering the log on boot?
+- we could just copy it to /run/log
+- if we have backfilling for shipped logs (we don't yet)
+ then we might want to ship it - but that may result in duplicate
+ logs if some of it was shipped before the crash
+
+perhaps we should truncate pmsg0 on orderly shutdown? or maybe it's
+good to see the late shutdown logs.
+
+Thu Dec 19 13:40:39 GMT 2024
+
+although we have PSTORE_foo in the omnia kconfig, I think this might
+be just because I copied it from RT3200
+
+Thu Dec 19 14:15:43 GMT 2024
+
+Omnia is not in ci.nix, and it's not trivial to add it because there
+is no output in the ci.nix configuration that makes sense for omnia.
+
+... OK, fixed by adding system-configuration as an independent module
+and importing in device config
+
+Thu Dec 19 21:59:47 GMT 2024
+
+The build-system shell script in outputs.systemConfiguration
+is ugly and requires we do bad things to avoid sucking build
+system stuff into the config
+
+I propose we make it a separate derivation.
+
+But first maybe we could improve some names
+
+Sun Dec 22 14:23:02 GMT 2024
+
+MT7622> echo $boot_default
+if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_for
+ever
+MT7622> echo $bootcmd
+if pstore check ; then run boot_recovery ; else run boot_ubi ; fi
+MT7622> echo $boot_ubi
+ubi part ubi && run boot_production ; run boot_recovery
+MT7622> echo $boot_production
+led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off
+MT7622> echo $ubi_read_production
+ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs
+MT7622> echo $ubi_prepare_rootfs
+if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi
+MT7622> echo $bootconf
+config-1
+MT7622> run boot_ubi
+UBI partition 'ubi' already selected
+No size specified -> Using max size (126976)
+Read 126976 bytes from volume fit to 0000000048000000
+
+## Checking Image at 48000000 ...
+Unknown image format!
+No size specified -> Using max size (7491584)
+Read 7491584 bytes from volume recovery to 0000000048000000
+## Loading kernel from FIT Image at 48000000 ...
+ Using 'config-1' configuration
+ Trying 'kernel-1' kernel subimage
+ Description: ARM64 OpenWrt Linux-6.6.45
+
+Sun Dec 22 17:39:56 GMT 2024
+
+From the output above it looks like the device I have plugged in has
+an openwrt "recovery" image but not a "production" image
+
+It also looks like it will be quite hard work to persuade it to boot
+from usb or anything. It doesn't have any of the extlinux stuff
+but it does have uefi for what that's worth
+
+default boot_production command reads a ubi volume called 'fit' and
+calls bootm on what it finds
+
+we could define boot_production to ubifsmount liminix; ubifs load
+<addr> <filename> (which is a fit) and bootm it. *presumably* we could
+do this from the openwrt recovery image
+
+but could we install the whole system using said recovery image? I
+expect we could do, it only requires getting a tarball onto it and
+unpacking it
+
+however, extlinux is not going to be helpful
+(actually it might be a bit, if we ask it to write the fit as
+well as/instead of the individual files)
+
+maybe we need separate concepts of "the filesystem contains
+stuff we need for boot" and "the stuff we need is the stuff
+that extlinux needs"
+
+each bootloader makes an output called bootfiles, and
+the bootablerootdir output copies from bootfiles
+
+Mon Dec 23 18:28:50 GMT 2024
+
+it might be worth moving ubi option decls into the hardware module, if
+they're hardware-dependent
diff --git a/bordervm-configuration.nix b/bordervm-configuration.nix
@@ -102,12 +102,18 @@ in {
systemd.services.sshd.wantedBy = pkgs.lib.mkForce [ "multi-user.target" ];
virtualisation = {
- forwardPorts = [ {
- from = "host";
- host.port = 7654;
-# guest.address = "10.0.2.15";
- guest.port =7654;
- } ];
+ forwardPorts = [
+ {
+ from = "host";
+ host.port = 7654;
+ # guest.address = "10.0.2.15";
+ guest.port =7654;
+ }
+ {
+ host.port = 2222;
+ guest.address = "10.0.2.15";
+ guest.port = 22;
+ }];
qemu = {
networkingOptions = [ ];
options =
diff --git a/ci.nix b/ci.nix
@@ -12,6 +12,7 @@ let
"qemu-armv7l"
"tp-archer-ax23"
"zyxel-nwa50ax"
+ "turris-omnia"
];
vanilla = ./vanilla-configuration.nix;
for-device = name:
diff --git a/devices/belkin-rt3200/default.nix b/devices/belkin-rt3200/default.nix
@@ -7,12 +7,10 @@
and is "work in progress" in Liminix.
.. note:: The factory flash image contains ECC errors that make it
- incompatible with Liminix: you need to use the `OpenWrt
+ incompatible with Liminix: use the `OpenWrt
UBI Installer <https://github.com/dangowrt/owrt-ubi-installer>`_ to
- rewrite the partition layout before you can flash
- Liminix onto it (or even use it with
- :ref:`system-outputs-tftpboot`, if you want the wireless
- to work).
+ rewrite the partition layout before you can use
+ Liminix with it
Hardware summary
================
@@ -27,8 +25,31 @@
Installation
============
- Installation is currently a manual process (you need a :ref:`serial <serial>` conection and
- TFTP) following the instructions at :ref:`system-outputs-ubimage`
+ Installation is currently a manual process.
+
+ Preparation
+ -----------
+
+ To prepare the device for Liminix you first need to use the
+ `OpenWrt UBI Installer
+ <https://github.com/dangowrt/owrt-ubi-installer>`_ image to
+ rewrite the flash layout. You can do this in onw of two ways:
+ either follow the instructions to do it through the vendor web
+ interface, or you can drop to U-boot and use TFTP
+
+ .. code-block:: console
+
+ MT7622> setenv ipaddr 10.0.0.6
+ MT7622> setenv serverip 10.0.0.1
+ MT7622> tftpboot 0x42000000 openwrt-mediatek-mt7622-linksys_e8450-ubi-initramfs-recovery-installer.itb
+ MT7622> bootm 0x42000000
+
+ Once it's finished booted into Linux you can safely reboot
+
+ Installing Liminix
+ ------------------
+
+ This is a manual process: you need a :ref:`serial <serial>` conection and TFTP : follow the instructions at :ref:`system-outputs-ubimage`
'';
@@ -192,7 +213,7 @@
rootDevice = "ubi0:liminix";
dts = {
src = "${openwrt.src}/target/linux/mediatek/dts/mt7622-linksys-e8450-ubi.dts";
- includes = [
+ includePaths = [
"${openwrt.src}/target/linux/mediatek/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
diff --git a/devices/gl-ar750/default.nix b/devices/gl-ar750/default.nix
@@ -52,8 +52,9 @@
'';
- module = {pkgs, config, lim, ... }:
+ module = {pkgs, config, lim, lib, ... }:
let
+ inherit (lib) mkIf;
openwrt = pkgs.openwrt;
firmwareBlobs = pkgs.pkgsBuildBuild.fetchFromGitHub {
owner = "kvalo";
@@ -116,9 +117,12 @@
rootDevice = "/dev/mtdblock5";
dts = {
src = "${openwrt.src}/target/linux/ath79/dts/qca9531_glinet_gl-ar750.dts";
- includes = [
+ includePaths = [
"${openwrt.src}/target/linux/ath79/dts"
];
+ includes = mkIf config.logging.persistent.enable [
+ ./pstore-ramoops.dtsi
+ ];
};
networkInterfaces =
diff --git a/devices/gl-ar750/pstore-ramoops.dtsi b/devices/gl-ar750/pstore-ramoops.dtsi
@@ -0,0 +1,9 @@
+/ {
+reserved-memory {
+ ramoops@03f00000 {
+ compatible = "ramoops";
+ reg = <0x03f00000 0x10000>;
+ pmsg-size = <0x10000>;
+ };
+ };
+};
diff --git a/devices/gl-mt300a/default.nix b/devices/gl-mt300a/default.nix
@@ -81,7 +81,7 @@
dts = {
src = "${openwrt.src}/target/linux/ramips/dts/mt7620a_glinet_gl-mt300a.dts";
- includes = [
+ includePaths = [
"${openwrt.src}/target/linux/ramips/dts"
];
};
diff --git a/devices/gl-mt300n-v2/default.nix b/devices/gl-mt300n-v2/default.nix
@@ -78,7 +78,7 @@
dts = {
src = "${openwrt.src}/target/linux/ramips/dts/mt7628an_glinet_gl-mt300n-v2.dts";
- includes = [
+ includePaths = [
"${openwrt.src}/target/linux/ramips/dts"
];
};
diff --git a/devices/qemu/default.nix b/devices/qemu/default.nix
@@ -66,7 +66,7 @@
# *correct* but it does at least boot
dts = lib.mkForce {
src = "${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/mti/malta.dts";
- includes = [
+ includePaths = [
"${config.system.outputs.kernel.modulesupport}/arch/mips/boot/dts/"
];
};
diff --git a/devices/tp-archer-ax23/default.nix b/devices/tp-archer-ax23/default.nix
@@ -405,7 +405,7 @@
rootDevice = "/dev/mtdblock3";
dts = {
src = "${openwrt.src}/target/linux/ramips/dts/mt7621_tplink_archer-ax23-v1.dts";
- includes = [
+ includePaths = [
"${openwrt.src}/target/linux/ramips/dts"
"${config.system.outputs.kernel.modulesupport}/arch/arm64/boot/dts/mediatek/"
];
diff --git a/devices/turris-omnia/default.nix b/devices/turris-omnia/default.nix
@@ -172,7 +172,6 @@
../../modules/arch/arm.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/mbrimage.nix
- ../../modules/outputs/extlinux.nix
];
config = {
@@ -224,11 +223,6 @@
# WARNING: unmet direct dependencies detected for ARCH_WANT_LIBATA_LEDS
ATA = "y";
- PSTORE = "y";
- PSTORE_RAM = "y";
- PSTORE_CONSOLE = "y";
-# PSTORE_DEFLATE_COMPRESS = "n";
-
BLOCK = "y";
MMC="y";
PWRSEQ_EMMC="y"; # ???
@@ -341,14 +335,14 @@
targets = ["ath9k" "ath10k_pci"];
};
in {
- defaultOutput = "mtdimage";
+ defaultOutput = "updater";
loadAddress = lim.parseInt "0x00800000"; # "0x00008000";
entryPoint = lim.parseInt "0x00800000"; # "0x00008000";
rootDevice = "/dev/mmcblk0p1";
dts = {
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts";
- includes = [
+ includePaths = [
"${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/marvell/"
];
};
diff --git a/devices/zyxel-nwa50ax/default.nix b/devices/zyxel-nwa50ax/default.nix
@@ -124,7 +124,7 @@
hash = "sha256-ifriAjWzFACrxVWCANZpUaEZgB/0pdbhnTVQytx6ddg=";
};
in {
- imports = [
+ imports = [
# We include it to ensure the bridge functionality
# is available on the target kernel.
../../modules/bridge
@@ -184,7 +184,7 @@
# Actually, this is not what we want.
# This DTS is insufficient.
src = ./mt7621_zyxel_nwa50ax.dtsi;
- includes = [
+ includePaths = [
# Here's one weird trick to make `ubi` detection
# out of the box.
# We will write ubi on /dev/firmware_a:rootfs location
@@ -233,7 +233,7 @@
services.zyxel-dual-image = config.boot.zyxel-dual-image.build {
ensureActiveImage = "primary";
# TODO: use mtd names rather…
- # primary and secondary are always /dev/mtd3 by virtue of the
+ # primary and secondary are always /dev/mtd3 by virtue of the
# dtb being not too wrong…
# TODO: remove this hack.
primaryMtdPartition = "/dev/mtd3";
diff --git a/doc/admin.rst b/doc/admin.rst
@@ -131,50 +131,54 @@ human-readable format, use :command:`s6-tai64nlocal`.
1970-01-02 21:51:48.832588765 wan.link.pppoe sent [LCP ConfReq id=0x1 <asyncmap 0x0> <magic 0x667a9594> <pcomp> <accom
p>]
+Log persistence
+---------------
+Logs written to :file:`/run/log/` will not survive a reboot or crash,
+as it is an ephemeral filesystem.
-Updating an installed system (JFFS2)
-************************************
+On supported hardware you can enable logging to `pstore
+<https://www.kernel.org/doc/Documentation/ABI/testing/pstore>`_ which
+means the most recent log messages will be preserved on reboot. Set
+the config option ``logging.persistent.enable = true`` to log messages
+to :file:`/dev/pmsg0` as well as to the regular log. This is a
+circular buffer, so when it fills up newer messages will overwrite the
+oldest messages.
-
-Adding packages
-===============
-
-If your device is running a JFFS2 root filesystem, you can build
-extra packages for it on your build system and copy them to the
-device: any package in Nixpkgs or in the Liminix overlay is available
-with the ``pkgs`` prefix:
+To check the previous messages after a (planned or forced) reboot,
+you need to mooun the pstore filesystem.
.. code-block:: console
- nix-build -I liminix-config=./my-configuration.nix \
- --arg device "import ./devices/mydevice" -A pkgs.tcpdump
+ # mount -t pstore pstore /sys/fs/pstore/
+ # ls -l /sys/fs/pstore/
+ -r--r--r-- 1 43071 pmsg-ramoops-0
+ # cat /sys/fs/pstore/pmsg-ramoops-0
+ @40000000000000282c997d29 mydevice klogd <6>[ 30.793756] int: port 2(wlan0) entered blocking state
+ [log messages from before the reboot follow]
- nix-shell -p min-copy-closure root@the-device result/
-Note that this only copies the package to the device: it doesn't update
-any profile to add it to ``$PATH``
+Updating an installed system
+****************************
-.. _rebuilding the system:
-
-Rebuilding the system
-=====================
+If your system has a writable root filesystem (JFFS2, btrfs etc -
+anything but squashfs), we have mechanisms for in-places updates
+analogous to :command:`nixos-rebuild`, but the operation is a bit
+different because it expects to run on a build machine and then copy
+to the host device using :command:`ssh`.
-Liminix has a mechanism for in-place updates of a running system which
-is analogous to :command:`nixos-rebuild`, but its operation is a
-bit different because it expects to run on a build machine and then
-copy to the host device. To use this, build the `outputs.systemConfiguration`
-target and then run the :command:`result/install.sh` script it generates.
+To use this, build the ``outputs.updater``
+target and then run the :command:`update.sh` script it generates.
.. code-block:: console
nix-build -I liminix-config=./my-configuration.nix \
--arg device "import ./devices/mydevice" \
- -A outputs.systemConfiguration
- ./result/install.sh root@the-device
+ -A outputs.updater
+ ./result/bin/update.sh root@the-device
-The install script uses min-copy-closure to copy new or changed
+The update script uses min-copy-closure to copy new or changed
packages to the device, then (perhaps) reboots it. The reboot
behaviour can be affected by flags:
@@ -187,7 +191,6 @@ behaviour can be affected by flags:
the services that have updated store paths (and anything that
depends on them), but will not affect services that haven't changed.
-
It doesn't delete old packages automatically: to do that run
:command:`min-collect-garbage`, which will delete any packages not in
the current system closure. Note that Liminix does not have the NixOS
@@ -207,6 +210,26 @@ Caveats
.. _levitate:
+Adding packages
+===============
+
+If you simply wish to add a package without any change to services,
+you can call :command:`min-copy-closure` directly to install
+any package in Nixpkgs or in the Liminix overlay
+
+.. code-block:: console
+
+ nix-build -I liminix-config=./my-configuration.nix \
+ --arg device "import ./devices/mydevice" -A pkgs.tcpdump
+
+ nix-shell -p min-copy-closure root@the-device result/
+
+Note that this only copies the package and its dependencies to the
+device: it doesn't update any profile to add it to ``$PATH``
+
+
+.. _rebuilding the system:
+
Reinstalling on a running system
********************************
diff --git a/examples/recovery.nix b/examples/recovery.nix
@@ -22,7 +22,6 @@ in rec {
../modules/outputs/ubimage.nix
../modules/outputs/jffs2.nix
../modules/outputs/ext4fs.nix
- ../modules/outputs/extlinux.nix
];
kernel.config = {
diff --git a/modules/all-modules.nix b/modules/all-modules.nix
@@ -30,7 +30,6 @@
./outputs/vmroot.nix
./ppp
./ramdisk.nix
- ./squashfs.nix
./ssh
./users.nix
./vlan
diff --git a/modules/hardware.nix b/modules/hardware.nix
@@ -24,11 +24,16 @@ in
only for QEMU.
'';
};
- includes = mkOption {
+ includePaths = mkOption {
default = [ ];
description = "List of directories to search for DTS includes (.dtsi files)";
type = types.listOf types.path;
};
+ includes = mkOption {
+ default = [ ];
+ description = "\"dtsi\" fragments to include in the generated device tree";
+ type = types.listOf types.path;
+ };
};
defaultOutput = mkOption {
description = "\"Default\" output: what gets built for this device when outputs.default is requested. Typically this is \"mtdimage\" or \"vmroot\"";
diff --git a/modules/kernel/default.nix b/modules/kernel/default.nix
@@ -68,19 +68,15 @@ in {
};
};
config = {
- system.outputs =
+ system.outputs.kernel =
let
mergedConfig = mergeConditionals
config.kernel.config
config.kernel.conditionalConfig;
- k = liminix.builders.kernel.override {
- config = mergedConfig;
- inherit (config.kernel) version src extraPatchPhase;
- targets = config.kernel.makeTargets;
- };
- in {
- kernel = k.vmlinux;
- zimage = k.zImage;
+ in liminix.builders.kernel.override {
+ config = mergedConfig;
+ inherit (config.kernel) version src extraPatchPhase;
+ targets = config.kernel.makeTargets;
};
kernel = rec {
diff --git a/modules/outputs.nix b/modules/outputs.nix
@@ -11,9 +11,12 @@ let
in
{
imports = [
- ./squashfs.nix
+ ./outputs/squashfs.nix
./outputs/vmroot.nix
- ./outputs/extlinux.nix
+ ./outputs/boot-extlinux.nix
+ ./outputs/boot-fit.nix
+ ./outputs/uimage.nix
+ ./outputs/updater
];
options = {
system.outputs = {
@@ -27,17 +30,7 @@ in
kernel
******
- Kernel vmlinux file (usually ELF)
- '';
- };
- zimage = mkOption {
- type = types.package;
- internal = true;
- description = ''
- zimage
- ******
-
- Kernel in compressed self-extracting package
+ Kernel package (multi-output derivation)
'';
};
dtb = mkOption {
@@ -50,16 +43,6 @@ in
Compiled device tree (FDT) for the target device
'';
};
- uimage = mkOption {
- type = types.package;
- internal = true;
- description = ''
- uimage
- ******
-
- Combined kernel and FDT in uImage (U-Boot compatible) format
- '';
- };
tplink-safeloader = mkOption {
type = types.package;
};
@@ -82,6 +65,12 @@ in
directory of files to package into root filesystem
'';
};
+ bootfiles = mkOption {
+ type = types.nullOr types.package;
+ internal = true;
+ default = null;
+ # description = "";
+ };
bootablerootdir = mkOption {
type = types.package;
internal = true;
@@ -104,18 +93,11 @@ in
system.outputs = rec {
dtb = liminix.builders.dtb {
inherit (config.boot) commandLine;
- dts = config.hardware.dts.src;
- includes = config.hardware.dts.includes ++ [
+ dts = [config.hardware.dts.src] ++ config.hardware.dts.includes;
+ includes = config.hardware.dts.includePaths ++ [
"${o.kernel.headers}/include"
];
};
- uimage = liminix.builders.uimage {
- commandLine = concatStringsSep " " config.boot.commandLine;
- inherit (config.boot) commandLineDtbNode;
- inherit (config.hardware) loadAddress entryPoint alignment;
- inherit (config.boot) imageFormat;
- inherit (o) kernel dtb;
- };
rootdir =
let
inherit (pkgs.pkgsBuildBuild) runCommand;
@@ -132,8 +114,8 @@ in
let inherit (pkgs.pkgsBuildBuild) runCommand;
in runCommand "add-slash-boot" { } ''
cp -a ${o.rootdir} $out
- ${if config.boot.loader.extlinux.enable
- then "(cd $out && chmod -R +w . && rmdir boot && cp -a ${o.extlinux} boot)"
+ ${if o.bootfiles != null
+ then "(cd $out && chmod -R +w . && rmdir boot && cp -a ${o.bootfiles} boot)"
else ""
}
'';
diff --git a/modules/outputs/boot-extlinux.nix b/modules/outputs/boot-extlinux.nix
@@ -0,0 +1,39 @@
+{
+ config
+, pkgs
+, lib
+, ...
+}:
+let
+ inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
+ inherit (pkgs.pseudofile) dir symlink;
+ cfg = config.boot.loader.extlinux;
+ o = config.system.outputs;
+ cmdline = concatStringsSep " " config.boot.commandLine;
+ wantsDtb = config.hardware.dts ? src && config.hardware.dts.src != null;
+in {
+ options.boot.loader.extlinux.enable = mkEnableOption "extlinux";
+
+ config = mkIf cfg.enable {
+ system.outputs.bootfiles = pkgs.runCommand "extlinux" {} ''
+ mkdir $out
+ cd $out
+ ${if wantsDtb then "cp ${o.dtb} dtb" else "true"}
+ cp ${o.initramfs} initramfs
+ cp ${o.kernel.zImage} kernel
+ mkdir extlinux
+ cat > extlinux/extlinux.conf << _EOF
+ menu title Liminix
+ timeout 40
+ label Liminix
+ kernel /boot/kernel
+ # initrd /boot/initramfs
+ append ${cmdline}
+ ${if wantsDtb then "fdt /boot/dtb" else ""}
+ _EOF
+ '';
+ filesystem = dir {
+ boot = symlink config.system.outputs.bootfiles;
+ };
+ };
+}
diff --git a/modules/outputs/boot-fit.nix b/modules/outputs/boot-fit.nix
@@ -0,0 +1,27 @@
+{
+ config
+, pkgs
+, lib
+, ...
+}:
+let
+ inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
+ inherit (pkgs.pseudofile) dir symlink;
+ cfg = config.boot.loader.fit;
+ o = config.system.outputs;
+ cmdline = concatStringsSep " " config.boot.commandLine;
+ wantsDtb = config.hardware.dts ? src && config.hardware.dts.src != null;
+in {
+ options.boot.loader.fit.enable = mkEnableOption "FIT in /boot";
+
+ config = mkIf cfg.enable {
+ system.outputs.bootfiles = pkgs.runCommand "boot-fit" {} ''
+ mkdir $out
+ cd $out
+ cp ${o.uimage} fit
+ '';
+ filesystem = dir {
+ boot = symlink config.system.outputs.bootfiles;
+ };
+ };
+}
diff --git a/modules/outputs/extlinux.nix b/modules/outputs/extlinux.nix
@@ -1,43 +0,0 @@
-{
- config
-, pkgs
-, lib
-, ...
-}:
-let
- inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
- inherit (pkgs.pseudofile) dir symlink;
- cfg = config.boot.loader.extlinux;
- o = config.system.outputs;
- cmdline = concatStringsSep " " config.boot.commandLine;
- wantsDtb = config.hardware.dts ? src && config.hardware.dts.src != null;
-in {
- options.system.outputs.extlinux = mkOption {
- type = types.package;
- # description = "";
- };
- options.boot.loader.extlinux.enable = mkEnableOption "extlinux";
-
- config = mkIf cfg.enable {
- system.outputs.extlinux = pkgs.runCommand "extlinux" {} ''
- mkdir $out
- cd $out
- ${if wantsDtb then "cp ${o.dtb} dtb" else "true"}
- cp ${o.initramfs} initramfs
- cp ${o.zimage} kernel
- mkdir extlinux
- cat > extlinux/extlinux.conf << _EOF
- menu title Liminix
- timeout 40
- label Liminix
- kernel /boot/kernel
- # initrd /boot/initramfs
- append ${cmdline}
- ${if wantsDtb then "fdt /boot/dtb" else ""}
- _EOF
- '';
- filesystem = dir {
- boot = symlink config.system.outputs.extlinux;
- };
- };
-}
diff --git a/modules/outputs/initramfs.nix b/modules/outputs/initramfs.nix
@@ -9,6 +9,7 @@ let
inherit (pkgs) runCommand;
in
{
+ imports = [ ./system-configuration.nix ];
options = {
boot.initramfs = {
enable = mkEnableOption "initramfs";
@@ -22,14 +23,6 @@ in
filesystem
'';
};
- systemConfiguration = mkOption {
- type = types.package;
- description = ''
- pkgs.systemconfig for the configured filesystem,
- contains 'activate' and 'init' commands
- '';
- internal = true;
- };
};
};
config = mkIf config.boot.initramfs.enable {
@@ -53,8 +46,6 @@ in
file /init ${pkgs.preinit}/bin/preinit 0755 0 0
SPECIALS
'';
- systemConfiguration =
- pkgs.systemconfig config.filesystem.contents;
};
};
}
diff --git a/modules/squashfs.nix b/modules/outputs/squashfs.nix
diff --git a/modules/outputs/system-configuration.nix b/modules/outputs/system-configuration.nix
@@ -0,0 +1,28 @@
+{
+ config
+, pkgs
+, lib
+, ...
+}:
+let
+ inherit (lib) mkEnableOption mkOption mkIf types;
+ inherit (pkgs) runCommand;
+in
+{
+ options = {
+ system.outputs = {
+ systemConfiguration = mkOption {
+ type = types.package;
+ description = ''
+ pkgs.systemconfig for the configured filesystem,
+ contains 'activate' and 'init' commands
+ '';
+ internal = true;
+ };
+ };
+ };
+ config = {
+ system.outputs.systemConfiguration =
+ pkgs.systemconfig config.filesystem.contents;
+ };
+}
diff --git a/modules/outputs/tftpboot.nix b/modules/outputs/tftpboot.nix
@@ -61,7 +61,7 @@ in {
o = config.system.outputs;
image = let choices = {
uimage = o.uimage;
- zimage = o.zimage;
+ zimage = o.kernel.zImage;
}; in choices.${cfg.kernelFormat};
bootCommand = let choices = {
uimage = "bootm";
diff --git a/modules/outputs/uimage.nix b/modules/outputs/uimage.nix
@@ -0,0 +1,30 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}:
+let
+ inherit (lib) mkOption types concatStringsSep;
+ inherit (pkgs) liminix writeText;
+ o = config.system.outputs;
+in
+{
+ options.system.outputs.uimage = mkOption {
+ type = types.package;
+ internal = true;
+ description = ''
+ uimage
+ ******
+
+ Combined kernel and FDT in uImage (U-Boot compatible) format
+ '';
+ };
+ config.system.outputs.uimage = liminix.builders.uimage {
+ commandLine = concatStringsSep " " config.boot.commandLine;
+ inherit (config.boot) commandLineDtbNode;
+ inherit (config.hardware) loadAddress entryPoint alignment;
+ inherit (config.boot) imageFormat;
+ inherit (o) kernel dtb;
+ };
+}
diff --git a/modules/outputs/updater/default.nix b/modules/outputs/updater/default.nix
@@ -0,0 +1,36 @@
+{
+ config
+, pkgs
+, lib
+, ...
+}:
+let
+ inherit (lib) mkIf;
+ o = config.system.outputs;
+ inherit (pkgs) runCommand;
+ inherit (lib) mkOption types;
+ inherit (pkgs.buildPackages) min-copy-closure;
+in
+{
+ imports = [ ../system-configuration.nix ];
+ options.system.outputs.updater = mkOption {
+ type = types.package;
+ description = ''
+ updater
+ ******
+
+ For configurations with a writable filesystem, create a shell
+ script that runs on the build system and updates the device
+ over the network to the new configuration
+ '';
+ };
+
+ config.system.outputs.updater =
+ runCommand "buildUpdater" { } ''
+ mkdir -p $out/bin
+ substitute ${./update.sh} $out/bin/update.sh \
+ --subst-var-by toplevel ${o.systemConfiguration} \
+ --subst-var-by min_copy_closure ${min-copy-closure}
+ chmod +x $out/bin/update.sh
+ '';
+}
diff --git a/modules/outputs/updater/update.sh b/modules/outputs/updater/update.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+
+# this shell script is run on the build system to min-copy-closure the
+# system configuration onto the device and reboot/restart services as
+# requested
+
+die() {
+ echo "$@"
+ exit 1
+}
+
+
+PATH=@min_copy_closure@/bin:$PATH
+ssh_command=${SSH_COMMAND-ssh}
+
+reboot="reboot"
+case "$1" in
+ "--no-reboot")
+ unset reboot
+ shift
+ ;;
+ "--fast")
+ reboot="soft"
+ shift
+ ;;
+esac
+
+target_host=$1
+shift
+
+test -n "$target_host" || \
+ die "Usage: $0 [--no-reboot] [--fast] target-host"
+
+toplevel=$(realpath @toplevel@)
+test -e $toplevel/etc/nix-store-paths || die "missing etc/nix-store-paths, is this really a system configuration?"
+echo installing from systemConfiguration $toplevel to host $target_host
+
+$ssh_command $target_host uname -a || die "Can't ssh to $target_host"
+min-copy-closure $target_host $toplevel
+set -x
+$ssh_command $target_host $toplevel/bin/install
+case "$reboot" in
+ reboot)
+ $ssh_command $target_host "sync; source /etc/profile; reboot"
+ ;;
+ soft)
+ $ssh_command $target_host $toplevel/bin/restart-services
+ ;;
+ *)
+ ;;
+esac
diff --git a/modules/s6/default.nix b/modules/s6/default.nix
@@ -7,10 +7,27 @@ let
s6-linux-init
stdenvNoCC;
inherit (lib.lists) unique concatMap;
+ inherit (lib) concatStrings;
+ inherit (builtins) map;
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs.liminix.services) oneshot bundle longrun;
inherit (lib) mkIf mkEnableOption mkOption types;
cfg = config.logging;
+
+ logger =
+ let pipecmds =
+ ["${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1"] ++
+ (lib.optional cfg.persistent.enable
+ "/bin/tee /dev/pmsg0") ++
+ (lib.optional cfg.shipping.enable
+ "${pkgs.logshipper}/bin/logtap ${cfg.shipping.socket} logshipper-socket-event");
+ in ''
+ #!${execline}/bin/execlineb -P
+ ${execline}/bin/redirfd -w 1 /dev/null
+ ${execline}/bin/redirfd -rnb 0 fifo
+ ${concatStrings (map (l: "pipeline { ${l} }\n") pipecmds)}
+ ${s6}/bin/s6-log -- ${cfg.directory}
+ '';
s6-rc-db =
let
# In the default bundle we need to have all the services
@@ -106,21 +123,7 @@ let
mode = "0600";
};
notification-fd = { file = "3"; };
- run = {
- file = ''
- #!${execline}/bin/execlineb -P
- ${execline}/bin/redirfd -w 1 /dev/null
- ${execline}/bin/redirfd -rnb 0 fifo
- ${if cfg.shipping.enable then ''
- pipeline { ${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1 }
- pipeline { ${pkgs.logshipper}/bin/logtap ${cfg.shipping.socket} logshipper-socket-event }
- ${s6}/bin/s6-log -- ${cfg.directory}
- '' else ''
- ${s6}/bin/s6-log -bpd3 -- ${cfg.script} ${cfg.directory}
- ''}
- '';
- mode = "0755";
- };
+ run = { file = logger; mode = "0755"; };
};
getty = dir {
run = {
@@ -212,6 +215,9 @@ let
in {
options = {
logging = {
+ persistent = {
+ enable = mkEnableOption "store logs across reboots";
+ };
shipping = {
enable = mkEnableOption "unix socket for log shipping";
socket = mkOption {
@@ -263,6 +269,11 @@ in {
)];
config = {
+ kernel.config = mkIf config.logging.persistent.enable {
+ PSTORE = "y";
+ PSTORE_PMSG = "y";
+ PSTORE_RAM = "y";
+ };
filesystem = dir {
etc = dir {
s6-rc = dir {
diff --git a/overlay.nix b/overlay.nix
@@ -218,11 +218,11 @@ extraPkgs // {
] ++ final.lib.optionals (o ? patches) o.patches;
});
- mtdutils = prev.mtdutils.overrideAttrs(o: {
+ mtdutils = (prev.mtdutils.overrideAttrs(o: {
patches = (if o ? patches then o.patches else []) ++ [
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
];
- });
+ })).override { util-linux = final.util-linux-small ; };
nftables = prev.nftables.overrideAttrs(o: {
configureFlags = [
diff --git a/pkgs/anoia/init.fnl b/pkgs/anoia/init.fnl
@@ -84,6 +84,8 @@
(false err) (expect (string.match err "path traversal"))))]
(expect= (append-path "/tmp" "hello") "/tmp/hello")
(expect= (append-path "/tmp/" "hello") "/tmp/hello")
+ (expect= (append-path "/tmp/" "///hello") "/tmp/hello")
+ (expect= (append-path "/tmp/" "///hello/../fish") "/tmp/fish")
(traps "/tmp/" "../hello")
(expect= (append-path "/tmp/" "hello/../goodbye") "/tmp/goodbye")
(traps "/tmp/" "hello/../../goodbye"))
diff --git a/pkgs/kernel/dtb.nix b/pkgs/kernel/dtb.nix
@@ -2,6 +2,8 @@
stdenv
, dtc
, lib
+, runCommand
+, writeText
}:
{ dts
, includes
@@ -10,14 +12,20 @@
cppDtSearchFlags = builtins.concatStringsSep " " (map (f: "-I${f}") includes);
dtcSearchFlags = builtins.concatStringsSep " " (map (f: "-i${f}") includes);
cmdline = lib.concatStringsSep " " commandLine;
+ chosen = writeText "chosen.dtsi" "/{ chosen { bootargs = ${builtins.toJSON cmdline}; }; };";
+ combined = writeText "combined-dts-fragments"
+ (lib.concatStrings
+ (builtins.map
+ (f: "#include \"${f}\"\n")
+ (dts ++ [ chosen ])));
in stdenv.mkDerivation {
name = "dtb";
phases = [ "buildPhase" ];
nativeBuildInputs = [ dtc ];
buildPhase = ''
- ${stdenv.cc.targetPrefix}cpp -nostdinc -x assembler-with-cpp ${cppDtSearchFlags} -undef -D__DTS__ -o dtb.tmp ${dts}
- echo '/{ chosen { bootargs = ${builtins.toJSON cmdline}; }; };' >> dtb.tmp
+ ${stdenv.cc.targetPrefix}cpp -nostdinc -x assembler-with-cpp ${cppDtSearchFlags} -undef -D__DTS__ -o dtb.tmp ${combined}
dtc ${dtcSearchFlags} -I dts -O dtb -o $out dtb.tmp
+ # dtc -I dtb -O dts $out
test -e $out
'';
}
diff --git a/pkgs/systemconfig/build-system-install.sh b/pkgs/systemconfig/build-system-install.sh
@@ -1,53 +0,0 @@
-#!/usr/bin/env bash
-
-# this shell script can be run on the build system to
-# min-copy-closure the system configuration onto the device
-# and reboot/restart services as requested
-
-die() {
- echo "$@"
- exit 1
-}
-
-# add min-copy-closure to the path. removing junk characters
-# inserted by default.nix (q.v.)
-min_copy_closure=@min-copy-closure@; PATH=${min_copy_closure//_/}/bin:$PATH
-
-ssh_command=${SSH_COMMAND-ssh}
-
-reboot="reboot"
-
-case "$1" in
- "--no-reboot")
- unset reboot
- shift
- ;;
- "--fast")
- reboot="soft"
- shift
- ;;
-esac
-
-target_host=$1
-shift
-
-test -n "$target_host" || \
- die "Usage: $0 [--no-reboot] [--fast] target-host"
-
-toplevel=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && readlink `pwd` )
-test -e $toplevel/etc/nix-store-paths || die "missing etc/nix-store-paths, is this really a system configuration?"
-echo installing from systemConfiguration $toplevel to host $target_host
-
-min-copy-closure $target_host $toplevel
-set -x
-$ssh_command $target_host $toplevel/bin/install
-case "$reboot" in
- reboot)
- $ssh_command $target_host "sync; source /etc/profile; reboot"
- ;;
- soft)
- $ssh_command $target_host $toplevel/bin/restart-services
- ;;
- *)
- ;;
-esac
diff --git a/pkgs/systemconfig/default.nix b/pkgs/systemconfig/default.nix
@@ -56,38 +56,33 @@ let
else "";
in "unlink(${qpathname}); ${cmd} ${chown}";
in mapAttrsToList (makeFile prefix) attrset;
- activateScript = attrset: writeText "makedevs.c" ''
- #include "defs.h"
- int main(int argc, char* argv[]) {
- chdir(argv[1]);
- ${(builtins.concatStringsSep "\n" (visit "." attrset))}
- }
- '';
in attrset:
- let makedevs = activateScript attrset;
+ let
+ activateScript = writeText "activate.c" ''
+ #include "defs.h"
+ int main(int argc, char* argv[]) {
+ chdir(argv[1]);
+ ${(builtins.concatStringsSep "\n" (visit "." attrset))}
+ }
+ '';
in stdenv.mkDerivation {
- name="make-stuff";
+ name="system-configuration";
src = ./.;
CFLAGS = "-Os";
LDFLAGS = "-static -Xlinker -static";
postConfigure = ''
- cp ${makedevs} makedevs.c
+ cp ${activateScript} activate.c
'';
- makeFlags = ["makedevs"];
+ makeFlags = ["activate"];
installPhase = ''
- closure=${closureInfo { rootPaths = [ makedevs ]; }}
+ closure=${closureInfo { rootPaths = [ activateScript ]; }}
mkdir -p $out/bin $out/etc
cp $closure/store-paths $out/etc/nix-store-paths
- $STRIP --remove-section=.note --remove-section=.comment --strip-all makedevs -o $out/bin/activate
+ $STRIP --remove-section=.note --remove-section=.comment --strip-all activate -o $out/bin/activate
ln -s ${s6-init-bin}/bin/init $out/bin/init
cp -p ${writeFennel "restart-services" {} ./restart-services.fnl} $out/bin/restart-services
- # obfuscate the store path of min-copy-closure so that the output
- # closure doesn't include a bunch of build system stuff
- f=${buildPackages.min-copy-closure}; f=$(echo $f | sed 's/\(.....\)/\1_/g')
- substitute ${./build-system-install.sh} $out/install.sh --subst-var-by min-copy-closure $f
- chmod +x $out/install.sh
cat > $out/bin/install <<EOF
#!/bin/sh -e
prefix=\''${1-/}
diff --git a/pkgs/tufted/tufted.fnl b/pkgs/tufted/tufted.fnl
@@ -16,10 +16,18 @@
(print (.. "TFTP serving from " options.base-directory))
-(fn merge-pathname [directory filename]
- (if (directory:match "/$")
- (.. directory filename)
- (.. directory "/" filename)))
+;; this is a copy of anoia append-path
+(fn merge-pathname [dirname filename]
+ (let [base (or (string.match dirname "(.*)/$") dirname)
+ result []]
+ (each [component (string.gmatch filename "([^/]+)")]
+ (if (and (= component "..") (> (# result) 0))
+ (table.remove result)
+ (= component "..")
+ (error "path traversal attempt")
+ true
+ (table.insert result component)))
+ (.. base "/" (table.concat result "/"))))
(->
(tftp:listen
diff --git a/shell.nix b/shell.nix
@@ -3,7 +3,6 @@ let
liminix = (import ./default.nix {
device = (import ./devices/qemu);
liminix-config = ./vanilla-configuration.nix;
- inherit nixpkgs;
});
here = builtins.toString ./.;
in liminix.buildEnv.overrideAttrs (o: {
diff --git a/tests/jffs2/configuration.nix b/tests/jffs2/configuration.nix
@@ -4,7 +4,7 @@ let
in {
imports = [
../../vanilla-configuration.nix
- ../../modules/squashfs.nix
+ ../../modules/outputs/squashfs.nix
../../modules/outputs/jffs2.nix
];
config.rootfsType = "jffs2";