1
0
forked from dan/liminix

Merge branch 'main' into linux-version-with-openwrt

This commit is contained in:
dan 2024-12-24 12:24:13 +00:00
commit 52967f746b
36 changed files with 498 additions and 175 deletions

24
NEWS
View File

@ -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.

View File

@ -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

View File

@ -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 =

1
ci.nix
View File

@ -12,6 +12,7 @@ let
"qemu-armv7l"
"tp-archer-ax23"
"zyxel-nwa50ax"
"turris-omnia"
];
vanilla = ./vanilla-configuration.nix;
for-device = name:

View File

@ -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/"
];

View File

@ -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 =

View File

@ -0,0 +1,9 @@
/ {
reserved-memory {
ramoops@03f00000 {
compatible = "ramoops";
reg = <0x03f00000 0x10000>;
pmsg-size = <0x10000>;
};
};
};

View File

@ -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"
];
};

View File

@ -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"
];
};

View File

@ -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/"
];
};

View File

@ -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/"
];

View File

@ -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/"
];
};

View File

@ -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";

View File

@ -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
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``
# 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]
.. _rebuilding the system:
Rebuilding the system
=====================
Updating an installed system
****************************
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.
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`.
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
********************************

View File

@ -22,7 +22,6 @@ in rec {
../modules/outputs/ubimage.nix
../modules/outputs/jffs2.nix
../modules/outputs/ext4fs.nix
../modules/outputs/extlinux.nix
];
kernel.config = {

View File

@ -30,7 +30,6 @@
./outputs/vmroot.nix
./ppp
./ramdisk.nix
./squashfs.nix
./ssh
./users.nix
./vlan

View File

@ -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\"";

View File

@ -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 {

View File

@ -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 ""
}
'';

View File

@ -12,19 +12,15 @@ let
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" {} ''
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.zimage} kernel
cp ${o.kernel.zImage} kernel
mkdir extlinux
cat > extlinux/extlinux.conf << _EOF
menu title Liminix
@ -37,7 +33,7 @@ in {
_EOF
'';
filesystem = dir {
boot = symlink config.system.outputs.extlinux;
boot = symlink config.system.outputs.bootfiles;
};
};
}

View File

@ -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;
};
};
}

View File

@ -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;
};
};
}

View File

@ -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;
};
}

View File

@ -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";

View File

@ -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;
};
}

View File

@ -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
'';
}

View File

@ -1,22 +1,19 @@
#!/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
# 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
}
# 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
PATH=@min_copy_closure@/bin:$PATH
ssh_command=${SSH_COMMAND-ssh}
reboot="reboot"
case "$1" in
"--no-reboot")
unset reboot
@ -34,10 +31,11 @@ shift
test -n "$target_host" || \
die "Usage: $0 [--no-reboot] [--fast] target-host"
toplevel=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && readlink `pwd` )
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

View File

@ -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 {

View File

@ -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 = [

View File

@ -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"))

View File

@ -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
'';
}

View File

@ -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-/}

View File

@ -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

View File

@ -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: {

View File

@ -4,7 +4,7 @@ let
in {
imports = [
../../vanilla-configuration.nix
../../modules/squashfs.nix
../../modules/outputs/squashfs.nix
../../modules/outputs/jffs2.nix
];
config.rootfsType = "jffs2";