Compare commits

..

No commits in common. "main" and "zyxel-activation" have entirely different histories.

94 changed files with 357 additions and 2138 deletions

View file

@ -1,50 +0,0 @@
name: build liminix
on:
pull_request:
types: [opened, synchronize, edited, reopened]
branches:
- main
push:
branches:
- main
jobs:
build_vm_qemu_mips:
runs-on: nix
steps:
- uses: actions/checkout@v3
- name: Build VM QEMU MIPS
run: |
# Enter the shell
nix-build ci.nix -A qemu
build_zyxel-nwa50ax_mips:
runs-on: nix
steps:
- uses: actions/checkout@v3
- name: Build VM QEMU MIPS
run: |
# Enter the shell
nix-build ci.nix -A qemu
test_hostapd:
runs-on: nix
steps:
- uses: actions/checkout@v3
- name: Build VM QEMU MIPS
run: |
# Enter the shell
nix-build ci.nix -A wlan
test_shell_customization:
runs-on: nix
steps:
- uses: actions/checkout@v3
- name: Build VM QEMU MIPS
run: |
# Enter the shell
nix-build ci.nix -A custom-shell

1
.gitignore vendored
View file

@ -7,4 +7,3 @@ _build
*-secrets.nix *-secrets.nix
examples/static-leases.nix examples/static-leases.nix
/doc/hardware.rst /doc/hardware.rst
.ccls-cache

View file

@ -4726,9 +4726,9 @@ outside of it
[X] 2) if so, convert it to lualinux [X] 2) if so, convert it to lualinux
[X] 3) add netlink socket to event loop [X] 3) add netlink socket to event loop
[X] 4) make it send messages to subscribers [X] 4) make it send messages to subscribers
[X] 5) package it 5) package it
[X] 6) make uevent-watcher use it instead of netlink directly 6) make uevent-watcher use it instead of netlink directly
[X] 7) write an inout test variant that has the stick inserted 7) write an inout test variant that has the stick inserted
at boot time already at boot time already
I'm also thinking we could wrap the raw fds from lualinux into small I'm also thinking we could wrap the raw fds from lualinux into small
@ -4741,167 +4741,3 @@ state before subscribing them [ needs a test ]
figure out what event format the subscribers want? lua-ish or send the figure out what event format the subscribers want? lua-ish or send the
same messages as udev would? If we're going to send the originals, same messages as udev would? If we're going to send the originals,
should we store them alongside the parsed, or reconstruct from parsed? should we store them alongside the parsed, or reconstruct from parsed?
Sat Apr 27 21:52:11 BST 2024
We have a passing inout test. Next thing to do is try it on
the actual arhcive hardware
Next big thing is some kind of failovery service. Almost-obvious
candidate is LTE failover with aaisp l2tp tunnel
Tue Apr 30 23:27:30 BST 2024
I want to connect my new ip camera to arthur without letting it reach the
internet, or the internet reach it.
we could plug it into a gl.inet box running dhcp server on lan
and client on wan, then use NAT to expose the camera's http and rtsp
ports on whatever address it has on the wan interface
Tue May 7 22:23:49 BST 2024
If we want to build a config with an l2tp upstream, it needs an
underlying dhcp interface not pppoe as we can't use the bordervm l2tp
account simultaneously. Having bordervm do dhcp might be quite useful
anyway for other applications, although it will have to double-nat to
the internet. We could give it an aaisp /64 and have routable ipv6 but
maybe that's a level of faff too high.
Given that we can build xl2tpd and a service for it.
're using the same l2tp account for thingy that we use to simulate ppp,
we need an upstream which is not ppp
We need a less shit coldplug that copes with filenames containing spaces (!)
Fri May 10 00:33:14 BST 2024
Getting xl2tp hackily running turned out to be not a lot of work. However,
we need to figure out routing
- we need a route on lan device to the dns to lookup l2tp.aaisp.net.uk
- we need a route on lan device to l2tp.aaisp.net.uk
also it doesn't die when the tunnel closes, which is a bit shit
maybe this is where we lean into health check services
a health check service is just a service that watches another service
and kills it if it's not healthy.
for xl2tpd, "not healthy" is "there is no ppp process" or "there is no
tunnel" or "the tunnel has no sessions". I don't know how we
(robustly) test for no ppp process associated with the l2tp peer
when ppp quits, does the tunnel come down?
in xl2tld.c child_handler we respond to sigchld by closing c->fd
and setting it to -1
Sat May 11 17:55:04 BST 2024
A better way to monitor the connection health would be to ping a
computer on the internet (preferably one that doesn't mind being
pinged). If we combine autodial with "is $isp still there" then we
should have something fairly robust.
xl2tpd spawns pppd, we should equip it with config that writes the
ppp outputs (ip address etc) to the xl2tp service directory so
that it can be used like a regular ppp. This will also make
it possible to have the health check work by pinging the peer address
Sun May 12 22:33:09 BST 2024
sleep until the interface is probably up
failure counter = 0
loop indefinitely
get outputs/peer-address of watched ppp service
ping it
if ok
reset failure counter
else
increment failure counter
fi
if failure counter > threshold
bounce the ppp service
exit, if previous action didn't do that already
end
sleep(check interval)
end loop
# ps ax | grep l2tp
72 root 1316 S s6-supervise l2tp.aaisp.net.uk.l2tp
73 root 1316 S s6-supervise l2tp.aaisp.net.uk.l2tp-log
122 root 1428 S {run.user} /bin/sh ./run.user l2tp.aaisp.net.uk.l2tp
1099 root 1428 S {run.user} /bin/sh ./run.user l2tp.aaisp.net.uk.l2tp
1102 root 1104 S {xl2tpd} /nix/store/i1bbqh7vybam03l6jzf4sm4np3k4ack5
1115 root 1420 S grep l2tp
# s6-rc -d change l2tp.aaisp.net.uk.l2tp
# ps ax | grep l2tp
72 root 1316 S s6-supervise l2tp.aaisp.net.uk.l2tp
73 root 1316 S s6-supervise l2tp.aaisp.net.uk.l2tp-log
122 root 1428 S {run.user} /bin/sh ./run.user l2tp.aaisp.net.uk.l2tp
1102 root 1104 S {xl2tpd} /nix/store/i1bbqh7vybam03l6jzf4sm4np3k4ack5
1122 root 1420 S grep l2tp
Mon May 13 19:45:59 BST 2024
We need to do the usb id swithcing dance thing for the lte modem.
At startup it's 12d1:14fe, which is "mass storage mode", although the
disks seem to disappear as soon as they appear which is weird
probably the mode switch should be triggered by device insertion
usb_modeswitch -v 12d1 -p 14fe --huawei-new-mode
https://github.com/pixelspark/tymodem?tab=readme-ov-file
Tue May 14 21:58:25 BST 2024
[ we didn't need this. the first form is the default, the second
is what something on the internet said we should change it to, the
third is setting it back to default ]
^SETPORT:A1,A2;12,1,16,A1,A2
AT^SETPORT="FF;12,16"
AT^SETPORT="A1,A2;12,1,16,A1,A2"
Wed May 15 21:55:11 BST 2024
we can use uevent-watch to look for devtype=usb_device product=12d1/14fe/102
and trigger a oneshot that runs usb-modeswitch
we can use uevent-watch to look for devtype=usb_device product=12d1/1506/102
and trigger a oneshot that runs the AT commands
if wwan0 is a triggered service how can dhcp depend on it? arse
- we can get reverse dependencies from s6-rc-db, so the sematics of
starting a triggered service could include starting everything it
enables
- we don't want to inadvertently start it on boot by putting it in the
global config.services
Thu May 16 09:09:44 BST 2024
we could do something cleverish with the config.services at build time
by stripping from it everything depending on a trigger. but then how
_do_ they get started? the intent of putting it in config.services
is that it will be started when conditions are suitable.
can we: go through each service in config.services, detect the trigger
that started it, and add it to a bundle named for that trigger?
we need something in the triggering service to mark the triggered
service as not-for-boot, and then to apply that transitively to
everyting depending on it
I don't think we have common code for triggers, so either we need to
add some or put this marking in all of the current examples

View file

@ -80,19 +80,8 @@ in {
}; };
}; };
services.openssh.enable = true; services.openssh.enable = true;
services.dnsmasq = {
enable = true;
resolveLocalQueries = false;
settings = {
# domain-needed = true;
dhcp-range = [ "10.0.0.10,10.0.0.240" ];
interface = "eth1";
};
};
systemd.services.sshd.wantedBy = pkgs.lib.mkForce [ "multi-user.target" ]; systemd.services.sshd.wantedBy = pkgs.lib.mkForce [ "multi-user.target" ];
virtualisation = { virtualisation = {
qemu = { qemu = {
networkingOptions = []; networkingOptions = [];
@ -133,11 +122,6 @@ in {
useDHCP = false; useDHCP = false;
ipv4.addresses = [ { address = "10.0.0.1"; prefixLength = 24;}]; ipv4.addresses = [ { address = "10.0.0.1"; prefixLength = 24;}];
}; };
nat = {
enable = true;
internalInterfaces = [ "eth1" ];
externalInterface ="eth0";
};
}; };
users.users.liminix = { users.users.liminix = {
isNormalUser = true; isNormalUser = true;

26
ci.nix
View file

@ -1,15 +1,21 @@
{ {
sources ? import ./lon.nix nixpkgs
, nixpkgs ? sources.nixpkgs , unstable
, unstable ? nixpkgs , liminix
, liminix ? ./.
, ... }: , ... }:
let let
pkgs = (import nixpkgs { }); inherit (builtins) map;
pkgs = (import nixpkgs {});
borderVmConf = ./bordervm.conf-example.nix; borderVmConf = ./bordervm.conf-example.nix;
inherit (pkgs.lib.attrsets) genAttrs mapAttrs; inherit (pkgs.lib.attrsets) genAttrs;
devices = [ devices = [
"gl-ar750"
"gl-mt300a"
"gl-mt300n-v2"
"qemu" "qemu"
"qemu-aarch64"
"qemu-armv7l"
"tp-archer-ax23"
"zyxel-nwa50ax" "zyxel-nwa50ax"
]; ];
vanilla = ./vanilla-configuration.nix; vanilla = ./vanilla-configuration.nix;
@ -19,7 +25,7 @@ let
device = import (liminix + "/devices/${name}"); device = import (liminix + "/devices/${name}");
liminix-config = vanilla; liminix-config = vanilla;
}).outputs.default; }).outputs.default;
tests = mapAttrs (_: v: v { inherit liminix nixpkgs; }) (import ./tests/ci.nix); tests = import ./tests/ci.nix;
jobs = jobs =
(genAttrs devices for-device) // (genAttrs devices for-device) //
tests // tests //
@ -38,6 +44,12 @@ let
imports = [ ./modules/all-modules.nix ]; imports = [ ./modules/all-modules.nix ];
}; };
}).outputs.optionsJson; }).outputs.optionsJson;
installers = map (f: "system.outputs.${f}") [
"vmroot"
"mtdimage"
"ubimage"
];
inherit (pkgs.lib) concatStringsSep;
in pkgs.stdenv.mkDerivation { in pkgs.stdenv.mkDerivation {
name = "liminix-doc"; name = "liminix-doc";
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [

View file

@ -4,61 +4,54 @@
, liminix-config ? <liminix-config> , liminix-config ? <liminix-config>
, nixpkgs ? <nixpkgs> , nixpkgs ? <nixpkgs>
, borderVmConf ? ./bordervm.conf.nix , borderVmConf ? ./bordervm.conf.nix
, imageType ? "primary"
}: }:
let let
overlay = import ./overlay.nix; overlay = import ./overlay.nix;
pkgs = import nixpkgs (device.system // { pkgs = import nixpkgs (device.system // {
overlays = [ overlay ]; overlays = [overlay];
config = { config = {
allowUnsupportedSystem = true; # mipsel allowUnsupportedSystem = true; # mipsel
permittedInsecurePackages = [ permittedInsecurePackages = [
"python-2.7.18.8" # kernel backports needs python <3 "python-2.7.18.6" # kernel backports needs python <3
"python-2.7.18.7"
]; ];
}; };
}); });
evalModules = (import ./lib/eval-config.nix { eval = pkgs.lib.evalModules {
inherit nixpkgs pkgs; specialArgs = {
inherit (pkgs) lib; modulesPath = builtins.toString ./modules;
}); };
eval = evalModules {
modules = [ modules = [
{ { _module.args = { inherit pkgs; inherit (pkgs) lim; }; }
nixpkgs = { ./modules/hardware.nix
source = nixpkgs; ./modules/base.nix
overlays = [ overlay ]; ./modules/busybox.nix
config.permittedInsecurePackages = [ ./modules/hostname.nix
"python-2.7.18.8" ./modules/kernel
];
};
}
device.module device.module
liminix-config liminix-config
./modules/s6
./modules/users.nix
./modules/outputs.nix
{
boot.imageType = imageType;
}
]; ];
}; };
config = eval.config; config = eval.config;
borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) { borderVm = ((import <nixpkgs/nixos/lib/eval-config.nix>) {
system = builtins.currentSystem; system = builtins.currentSystem;
modules = [ modules = [
{ ({ ... } : { nixpkgs.overlays = [ overlay ]; })
nixpkgs.overlays = [
(final: prev: {
go-l2tp = final.callPackage ./pkgs/go-l2tp {};
tufted = final.callPackage ./pkgs/tufted {};
})
];
}
(import ./bordervm-configuration.nix) (import ./bordervm-configuration.nix)
borderVmConf borderVmConf
]; ];
}).config.system; }).config.system;
in { in {
inherit evalModules;
outputs = config.system.outputs // { outputs = config.system.outputs // {
default = config.system.outputs.${config.hardware.defaultOutput}; default = config.system.outputs.${config.hardware.defaultOutput};
optionsJson = optionsJson =
@ -73,13 +66,6 @@ in {
# cross-compiling nix-shell for any package we're customizing # cross-compiling nix-shell for any package we're customizing
inherit pkgs; inherit pkgs;
deployEnv = pkgs.mkShell {
packages = with pkgs.pkgsBuildBuild; [
tufted
min-copy-closure
];
};
buildEnv = pkgs.mkShell { buildEnv = pkgs.mkShell {
packages = with pkgs.pkgsBuildBuild; [ packages = with pkgs.pkgsBuildBuild; [
tufted tufted

View file

@ -125,14 +125,8 @@
networkInterfaces = networkInterfaces =
let inherit (config.system.service.network) link; let inherit (config.system.service.network) link;
in { in {
lan = link.build { lan = link.build { ifname = "eth0"; };
ifname = "lan"; wan = link.build { ifname = "eth1"; };
devpath = "/devices/platform/ahb/19000000.eth";
};
wan = link.build {
ifname = "wan";
devpath = "/devices/platform/ahb/1a000000.eth";
};
wlan = link.build { wlan = link.build {
ifname = "wlan0"; ifname = "wlan0";
dependencies = [ mac80211 ]; dependencies = [ mac80211 ];
@ -155,7 +149,6 @@
}; };
boot.tftp = { boot.tftp = {
loadAddress = lim.parseInt "0x00A00000"; loadAddress = lim.parseInt "0x00A00000";
appendDTB = true;
}; };
kernel = { kernel = {
src = pkgs.pkgsBuildBuild.fetchurl { src = pkgs.pkgsBuildBuild.fetchurl {

View file

@ -1,7 +1,7 @@
# This "device" generates images that can be used with the QEMU # This "device" generates images that can be used with the QEMU
# emulator. The default output is a directory containing separate # emulator. The default output is a directory containing separate
# kernel (uncompressed vmlinux) and initrd (squashfs) images # kernel (uncompressed vmlinux) and initrd (squashfs) images
rec { {
system = { system = {
crossSystem = { crossSystem = {
config = "mips-unknown-linux-musl"; config = "mips-unknown-linux-musl";
@ -41,9 +41,6 @@ rec {
../../modules/arch/mipseb.nix ../../modules/arch/mipseb.nix
../families/qemu.nix ../families/qemu.nix
]; ];
nixpkgs.hostPlatform = system.crossSystem;
kernel = { kernel = {
config = { config = {
MIPS_MALTA= "y"; MIPS_MALTA= "y";

View file

@ -56,7 +56,7 @@
}; };
partition@400000 { partition@400000 {
label = "ubi_a"; label = "ubi";
reg = <0x800000 0x2000000>; reg = <0x800000 0x2000000>;
}; };
}; };

View file

@ -0,0 +1,155 @@
#include "mt7621.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
/ {
aliases {
label-mac-device = &gmac0;
};
};
&nand {
status = "okay";
mediatek,nmbm;
mediatek,bmt-max-ratio = <15>;
mediatek,bmt-max-reserved-blocks = <64>;
mediatek,bmt-remap-range =
<0x0 0x980000>,
<0x2980000 0x7800000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x0 0x80000>;
read-only;
};
partition@80000 {
label = "u-boot-env";
reg = <0x80000 0x80000>;
read-only;
};
factory: partition@100000 {
label = "factory";
reg = <0x100000 0x80000>;
read-only;
};
partition@2980000 {
label = "firmware_b";
reg = <0x2980000 0x2800000>;
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "kernel_b";
reg = <0x0 0x800000>;
};
partition@400000 {
label = "ubi";
reg = <0x800000 0x2000000>;
};
};
partition@180000 {
label = "firmware_a";
reg = <0x180000 0x2800000>;
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "kernel_a";
reg = <0x0 0x800000>;
};
partition@400000 {
label = "ubi_a";
reg = <0x800000 0x2000000>;
};
};
partition@5180000 {
label = "rootfs_data";
reg = <0x5180000 0x1400000>;
};
partition@6580000 {
label = "logs";
reg = <0x6580000 0xd00000>;
};
partition@7280000 {
label = "vendor-myzyxel";
reg = <0x7280000 0x480000>;
read-only;
};
partition@7700000 {
label = "bootconfig";
reg = <0x7700000 0x80000>;
};
mrd: partition@7780000 {
label = "mrd";
reg = <0x7780000 0x80000>;
read-only;
nvmem-layout {
compatible = "fixed-layout";
#address-cells = <1>;
#size-cells = <1>;
macaddr_mrd_1fff8: macaddr@1fff8 {
reg = <0x1fff8 0x6>;
};
};
};
};
};
&pcie {
status = "okay";
};
&pcie1 {
wlan_5g: wifi@0,0 {
reg = <0x0 0 0 0 0>;
compatible = "mediatek,mt76";
mediatek,mtd-eeprom = <&factory 0x0>;
/* MAC-Address set in userspace */
};
};
&gmac0 {
nvmem-cells = <&macaddr_mrd_1fff8>;
nvmem-cell-names = "mac-address";
};
&switch0 {
ports {
port@4 {
status = "okay";
label = "lan";
};
};
};
&state_default {
gpio {
groups = "uart3";
function = "gpio";
};
};

View file

@ -1,4 +1,4 @@
rec { {
system = { system = {
crossSystem = { crossSystem = {
config = "mipsel-unknown-linux-musl"; config = "mipsel-unknown-linux-musl";
@ -91,6 +91,7 @@ rec {
- Mount the logs partition, mount / as overlayfs of firmware ? rootfs and rootfs_data for extended data. - Mount the logs partition, mount / as overlayfs of firmware ? rootfs and rootfs_data for extended data.
- Jitter-based entropy injection? Device can be slow to initialize its CRNG and hostapd will reject few clients at the start because of that. - Jitter-based entropy injection? Device can be slow to initialize its CRNG and hostapd will reject few clients at the start because of that.
- Defaults for hostapd based on MT7915 capabilities? See the example for one possible list. - Defaults for hostapd based on MT7915 capabilities? See the example for one possible list.
- Remove primary/secondary hack and put it in preinit.
- Offer ways to reflash the *bootloader* itself to support direct boot via UBI and kernel upgrades via filesystem rewrite. - Offer ways to reflash the *bootloader* itself to support direct boot via UBI and kernel upgrades via filesystem rewrite.
Vendor web page: https://www.zyxel.com/fr/fr/products/wireless/ax1800-wifi-6-dual-radio-nebulaflex-access-point-nwa50ax Vendor web page: https://www.zyxel.com/fr/fr/products/wireless/ax1800-wifi-6-dual-radio-nebulaflex-access-point-nwa50ax
@ -135,8 +136,6 @@ rec {
../../modules/zyxel-dual-image ../../modules/zyxel-dual-image
]; ];
nixpkgs.hostPlatform = system.crossSystem;
filesystem = dir { filesystem = dir {
lib = dir { lib = dir {
firmware = dir { firmware = dir {
@ -172,8 +171,6 @@ rec {
maxLEBcount = "256"; maxLEBcount = "256";
}; };
flash.eraseBlockSize = 64 * 1024;
# This is a FIT containing a kernel padded and # This is a FIT containing a kernel padded and
# a UBI volume rootfs. # a UBI volume rootfs.
defaultOutput = "zyxel-nwa-fit"; defaultOutput = "zyxel-nwa-fit";
@ -183,19 +180,23 @@ rec {
# Aligned on 2kb. # Aligned on 2kb.
alignment = 2048; alignment = 2048;
rootDevice = "ubi0:rootfs"; rootDevice = "ubi:rootfs";
alternativeRootDevice = "ubi1:rootfs";
# Auto-attach MTD devices: ubi_a then ubi_b.
ubi.mtds = [ "ubi_a" "ubi_b" ];
dts = { dts = {
# Strong DTB assumptions: # Actually, this is not what we want.
# ubi_a and ubi_b are two MTD devices. # This DTS is insufficient.
# If those changes, disaster will occur. src = ./mt7621_zyxel_nwa50ax.dtsi;
src = ./dtb/mt7621_zyxel_nwa50ax.dtsi;
includes = [ includes = [
"${./dtb}" # Here's one weird trick to make `ubi` detection
# out of the box.
# We will write ubi on /dev/firmware_a:rootfs location
# and same for /dev/firmware_b:rootfs.
# How do we distinguish both?
# We can just use the DTS to point ubi at A or B.
# This, unfortunately, means that we have "two images".
# But they are really just 1 image with 2 different DTS.
# TODO: improve this hack in preinit?
(if config.boot.imageType == "primary" then "${./a_image}" else "${./b_image}")
"${openwrt.src}/target/linux/ramips/dts" "${openwrt.src}/target/linux/ramips/dts"
]; ];
}; };
@ -224,9 +225,8 @@ rec {
imageFormat = "fit"; imageFormat = "fit";
tftp = { tftp = {
# 20MB is pretty good on this device as we have plenty of RAM. # 5MB is nice.
freeSpaceBytes = 20 * 1024 * 1024; freeSpaceBytes = 5 * 1024 * 1024;
appendDTB = true;
loadAddress = lim.parseInt "0x2000000"; loadAddress = lim.parseInt "0x2000000";
}; };
}; };

View file

@ -18,8 +18,8 @@
in rec { in rec {
boot = { boot = {
tftp = { tftp = {
serverip = "10.0.0.1"; serverip = "192.168.8.148";
ipaddr = "10.0.0.8"; ipaddr = "192.168.8.251";
}; };
}; };
@ -124,7 +124,9 @@ in rec {
users.root = { users.root = {
passwd = lib.mkForce secrets.root.passwd; passwd = lib.mkForce secrets.root.passwd;
openssh.authorizedKeys.keys = secrets.root.keys; # openssh.authorizedKeys.keys = [
# (builtins.readFile "/home/dan/.ssh/id_rsa.pub")
# ];
}; };
users.backup = { users.backup = {

View file

@ -41,13 +41,4 @@ in rec {
defaultProfile.packages = with pkgs; [ defaultProfile.packages = with pkgs; [
figlet figlet
]; ];
nixpkgs.hostPlatform = lib.mkDefault {
config = "mips-unknown-linux-musl";
gcc = {
abi = "32";
arch = "mips32"; # maybe mips_24kc-
};
};
nixpkgs.buildPlatform = lib.mkDefault "x86_64-linux";
} }

View file

@ -1,93 +0,0 @@
{
config,
pkgs,
lib,
...
}: let
secrets = import ./extneder-secrets.nix;
rsecrets = import ./rotuer-secrets.nix;
lns = "l2tp.aaisp.net.uk";
inherit (pkgs.liminix.services) oneshot longrun bundle target;
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs) writeText dropbear ifwait serviceFns;
svc = config.system.service;
in rec {
boot = {
tftp = {
serverip = "10.0.0.1";
ipaddr = "10.0.0.8";
};
};
imports = [
../modules/cdc-ncm
../modules/network
../modules/vlan
../modules/ssh
../modules/usb.nix
../modules/watchdog
../modules/mount
../modules/ppp
];
hostname = "thing";
services.wwan = svc.wwan.build {
apn = "data.uk";
username = "user";
password = "one2one";
authType = "chap";
};
services.dhcpc = svc.network.dhcp.client.build {
interface = config.services.wwan;
dependencies = [ config.services.hostname ];
};
services.sshd = svc.ssh.build { };
services.resolvconf = oneshot rec {
dependencies = [ services.dhcpc ];
name = "resolvconf";
up = ''
. ${serviceFns}
( in_outputs ${name}
for i in $(output ${services.dhcpc} dns); do
echo "nameserver $i" > resolv.conf
done
)
'';
};
filesystem = dir {
etc = dir {
"resolv.conf" = symlink "${services.resolvconf}/.outputs/resolv.conf";
};
srv = dir {};
};
services.lnsroute = svc.network.route.build {
via = "$(output ${services.dhcpc} router)";
target = lns;
dependencies = [services.dhcpc];
};
services.l2tp = svc.l2tp.build {
inherit lns;
ppp-options = [
"debug" "+ipv6" "noauth"
"name" rsecrets.l2tp.name
"password" rsecrets.l2tp.password
];
dependencies = [ services.lnsroute ];
};
services.defaultroute4 = svc.network.route.build {
via = "$(output ${services.l2tp} router)";
target = "default";
dependencies = [services.l2tp];
};
users.root = {
passwd = lib.mkForce secrets.root.passwd;
openssh.authorizedKeys.keys = secrets.root.keys;
};
}

View file

@ -1,24 +0,0 @@
{ nixpkgs ? <nixpkgs>, pkgs ? (import nixpkgs {}), lib ? pkgs.lib }:
args:
let
modulesPath = builtins.toString ../modules;
in
# FIXME: we could replace the `lib` by a lib-only minimal nixpkgs.
(import "${nixpkgs}/lib/modules.nix" { inherit lib; }).evalModules (args // {
specialArgs = (args.specialArgs or {}) // {
inherit modulesPath;
};
modules = (args.modules or []) ++ [
"${modulesPath}/hardware.nix"
"${modulesPath}/base.nix"
"${modulesPath}/busybox.nix"
"${modulesPath}/hostname.nix"
"${modulesPath}/kernel"
"${modulesPath}/s6"
"${modulesPath}/users.nix"
"${modulesPath}/outputs.nix"
"${modulesPath}/nixpkgs.nix"
"${modulesPath}/misc/assertions.nix"
# FIXME: we should let the caller inject `pkgs` and `lim` ideally...
];
})

View file

@ -1,15 +0,0 @@
{
"version": "1",
"sources": {
"nixpkgs": {
"type": "GitHub",
"fetchType": "tarball",
"owner": "nixos",
"repo": "nixpkgs",
"branch": "nixos-unstable-small",
"revision": "b6227cadb5123c7e4cb159bf6f9f5705ae081a47",
"url": "https://github.com/nixos/nixpkgs/archive/b6227cadb5123c7e4cb159bf6f9f5705ae081a47.tar.gz",
"hash": "sha256-KFR30GNFhjzXl0kVEn+KK4xrFr0gggb1NBroP8ukbxY="
}
}
}

41
lon.nix
View file

@ -1,41 +0,0 @@
# Generated by lon. Do not modify!
let
lock = builtins.fromJSON (builtins.readFile ./lon.lock);
# Override with a path defined in an environment variable. If no variable is
# set, the original path is used.
overrideFromEnv =
name: path:
let
replacement = builtins.getEnv "LON_OVERRIDE_${name}";
in
if replacement == "" then
path
else
# this turns the string into an actual Nix path (for both absolute and
# relative paths)
if builtins.substring 0 1 replacement == "/" then
/. + replacement
else
/. + builtins.getEnv "PWD" + "/${replacement}";
fetchSource =
args@{ fetchType, ... }:
if fetchType == "git" then
builtins.fetchGit {
url = args.url;
ref = args.branch;
rev = args.revision;
narHash = args.hash;
}
else if fetchType == "tarball" then
builtins.fetchTarball {
url = args.url;
sha256 = args.hash;
}
else
builtins.throw "Unsupported source type ${fetchType}";
in
builtins.mapAttrs (name: args: overrideFromEnv name (fetchSource args)) lock.sources

View file

@ -8,7 +8,6 @@
./bridge ./bridge
./busybox.nix ./busybox.nix
./dhcp6c ./dhcp6c
./jitter-rng
./dnsmasq ./dnsmasq
./firewall ./firewall
./hardware.nix ./hardware.nix
@ -37,6 +36,5 @@
./vlan ./vlan
./watchdog ./watchdog
./wlan.nix ./wlan.nix
./nixpkgs.nix
]; ];
} }

View file

@ -14,8 +14,5 @@
boot.commandLine = [ boot.commandLine = [
"console=ttyS0,115200" # true of all mips we've yet encountered "console=ttyS0,115200" # true of all mips we've yet encountered
]; ];
boot.tftp.commandLine = [
"console=ttyS0,115200" # true of all mips we've yet encountered
];
}; };
} }

View file

@ -4,13 +4,11 @@
{ lib, pkgs, config, ...}: { lib, pkgs, config, ...}:
let let
inherit (lib) mkEnableOption mkOption types isDerivation hasAttr concatStringsSep mapAttrsToList; inherit (lib) mkEnableOption mkOption types isDerivation hasAttr ;
inherit (pkgs.pseudofile) dir symlink; inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs.liminix.networking) address interface; inherit (pkgs.liminix.networking) address interface;
inherit (pkgs.liminix.services) bundle; inherit (pkgs.liminix.services) bundle;
# TODO: escape shell argument.
exportVar = name: value: "export ${name}=\"${value}\"";
type_service = pkgs.liminix.lib.types.service; type_service = pkgs.liminix.lib.types.service;
in { in {
@ -24,24 +22,6 @@ in {
/run/current-system, we just add the paths in /etc/profile /run/current-system, we just add the paths in /etc/profile
''; '';
}; };
environmentVariables = mkOption {
type = types.attrsOf types.str;
description = ''
Attribute set of environment variables to make available
in a login shell.
The value is assumed to be escaped and the name to be valid.
'';
};
prompt = mkOption {
type = types.str;
default = "$(whoami)@$(hostname) # ";
description = ''
Prompt string (PS1) for the shell.
'';
};
}; };
services = mkOption { services = mkOption {
type = types.attrsOf type_service; type = types.attrsOf type_service;
@ -84,19 +64,15 @@ in {
default = "bootargs"; default = "bootargs";
description = "Kernel command line's devicetree node"; description = "Kernel command line's devicetree node";
}; };
imageType = mkOption {
type = types.enum [ "primary" "secondary" ];
default = "primary";
};
imageFormat = mkOption { imageFormat = mkOption {
type = types.enum ["fit" "uimage"]; type = types.enum ["fit" "uimage"];
default = "uimage"; default = "uimage";
}; };
tftp = { tftp = {
commandLine = mkOption {
type = types.listOf types.str;
default = config.boot.commandLine;
description = ''
TFTP-specific command line.
Defaults to the classical one if unset.
'';
};
loadAddress = mkOption { loadAddress = mkOption {
type = types.ints.unsigned; type = types.ints.unsigned;
description = '' description = ''
@ -126,29 +102,15 @@ in {
}; };
}; };
config = { config = {
# By default, we enable cross-compilation support.
nixpkgs.buildPlatform = lib.mkDefault builtins.currentSystem;
defaultProfile.packages = with pkgs; defaultProfile.packages = with pkgs;
[ s6 s6-init-bin execline s6-linux-init s6-rc ]; [ s6 s6-init-bin execline s6-linux-init s6-rc ];
# Set the useful PS1 prompt by default.
defaultProfile.environmentVariables.PS1 = lib.mkDefault config.defaultProfile.prompt;
boot.commandLine = [ boot.commandLine = [
"panic=10 oops=panic init=/bin/init loglevel=8" "panic=10 oops=panic init=/bin/init loglevel=8"
"root=${config.hardware.rootDevice}" "root=${config.hardware.rootDevice}"
"rootfstype=${config.rootfsType}" "rootfstype=${config.rootfsType}"
"fw_devlink=off" "fw_devlink=off"
] ] ++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}";
++ (map (mtd: "ubi.mtd=${mtd}") config.hardware.ubi.mtds)
++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}"
++ lib.optional (config.hardware.alternativeRootDevice != null) "rootalt=${config.hardware.alternativeRootDevice}";
boot.tftp.commandLine = [
"panic=10 oops=panic init=/bin/init loglevel=8"
"fw_devlink=off"
"rootfstype=${config.rootfsType}"
];
system.callService = path : parameters : system.callService = path : parameters :
let let
@ -203,10 +165,9 @@ in {
etc = let etc = let
profile = symlink profile = symlink
(pkgs.writeScript ".profile" '' (pkgs.writeScript ".profile" ''
PATH=${lib.makeBinPath config.defaultProfile.packages}:/bin PATH=${lib.makeBinPath config.defaultProfile.packages}:/bin
export PATH export PATH
${concatStringsSep "\n" (mapAttrsToList exportVar config.defaultProfile.environmentVariables)} '');
'');
in dir { in dir {
inherit profile; inherit profile;
ashrc = profile; ashrc = profile;

View file

@ -20,7 +20,6 @@ in
system.service.bridge = { system.service.bridge = {
primary = mkOption { type = liminix.lib.types.serviceDefn; }; primary = mkOption { type = liminix.lib.types.serviceDefn; };
members = mkOption { type = liminix.lib.types.serviceDefn; }; members = mkOption { type = liminix.lib.types.serviceDefn; };
ready = mkOption { type = liminix.lib.types.serviceDefn; };
}; };
}; };
config.system.service.bridge = { config.system.service.bridge = {
@ -29,12 +28,6 @@ in
type = types.str; type = types.str;
description = "bridge interface name to create"; description = "bridge interface name to create";
}; };
macAddressFromInterface = mkOption {
type = types.nullOr liminix.lib.types.service;
default = null;
description = "reuse mac address from an existing interface service";
};
}; };
members = config.system.callService ./members.nix { members = config.system.callService ./members.nix {
primary = mkOption { primary = mkOption {
@ -43,33 +36,8 @@ in
}; };
members = mkOption { members = mkOption {
type = types.attrsOf (types.submodule ({ ... }: { options = { type = types.listOf liminix.lib.types.interface;
member = mkOption { description = "interfaces to add to the bridge";
type = liminix.lib.types.interface;
description = "interface to add";
};
dependencies = mkOption {
type = types.listOf liminix.lib.types.service;
default = [];
description = "extra dependencies before attaching this interface to the bridge";
};
}; }));
description = "set of bridge members";
};
};
# TODO: generalize it outside
ready = config.system.callService ./ready.nix {
primary = mkOption {
type = liminix.lib.types.service;
description = "primary bridge interface";
};
members = mkOption {
type = liminix.lib.types.service;
description = "members service";
}; };
}; };
}; };

View file

@ -7,22 +7,26 @@
{ members, primary } : { members, primary } :
let let
inherit (liminix.services) structuredBundle oneshot; inherit (liminix.networking) interface;
inherit (lib) mapAttrs; inherit (liminix.services) bundle oneshot;
addif = name: { dependencies ? [ ], member }: oneshot { inherit (lib) mkOption types;
name = "${primary.name}.member.${name}"; addif = member :
up = '' # how do we get sight of services from here? maybe we need to
echo "attaching $(output ${member} ifname) to $(output ${primary} ifname) bridge" # implement ifwait as a regualr derivation instead of a
ip link set dev $(output ${member} ifname) master $(output ${primary} ifname) # servicedefinition
''; svc.ifwait.build {
down = '' state = "running";
echo "detaching $(output ${member} ifname) from any bridge" interface = member;
ip link set dev $(output ${member} ifname) nomaster dependencies = [ primary member ];
''; service = oneshot {
name = "${primary.name}.member.${member.name}";
dependencies = [ primary member ] ++ dependencies; up = ''
}; ip link set dev $(output ${member} ifname) master $(output ${primary} ifname)
in structuredBundle { '';
down = "ip link set dev $(output ${member} ifname) nomaster";
};
};
in bundle {
name = "${primary.name}.members"; name = "${primary.name}.members";
contents = mapAttrs addif members; contents = map addif members;
} }

View file

@ -3,24 +3,15 @@
, ifwait , ifwait
, lib , lib
}: }:
{ ifname, macAddressFromInterface ? null } : { ifname } :
let let
inherit (liminix.services) bundle oneshot; inherit (liminix.services) bundle oneshot;
inherit (lib) mkOption types optional; inherit (lib) mkOption types;
in oneshot rec { in oneshot rec {
name = "${ifname}.link"; name = "${ifname}.link";
up = '' up = ''
${if macAddressFromInterface == null then ip link add name ${ifname} type bridge
"ip link add name ${ifname} type bridge" ${liminix.networking.ifup name ifname}
else
"ip link add name ${ifname} address $(output ${macAddressFromInterface} ether) type bridge"}
(in_outputs ${name}
echo ${ifname} > ifname
cat /sys/class/net/${ifname}/address > ether
)
''; '';
down = "ip link delete ${ifname}"; down = "ip link set down dev ${ifname}";
dependencies = optional (macAddressFromInterface != null) macAddressFromInterface;
} }

View file

@ -1,18 +0,0 @@
{
liminix
, ifwait
, lib
}:
{ primary, members } :
let
inherit (liminix.services) oneshot;
in oneshot {
name = "${primary.name}.oper";
up = ''
ip link set up dev $(output ${primary} ifname)
${ifwait}/bin/ifwait -v $(output ${primary} ifname) running
'';
down = "ip link set down dev $(output ${primary} ifname)";
dependencies = [ members ];
}

View file

@ -1,28 +0,0 @@
{ config, pkgs, lib, ... }:
let
inherit (pkgs) liminix;
inherit (lib) mkOption types;
svc = config.system.service;
in {
options = {
system.service.wwan = mkOption {
type = liminix.lib.types.serviceDefn;
};
};
config = {
kernel.config = {
USB_NET_HUAWEI_CDC_NCM = "y";
USB_USBNET = "y";
USB_SERIAL = "y";
USB_SERIAL_OPTION = "y";
};
# https://www.0xf8.org/2017/01/flashing-a-huawei-e3372h-4g-lte-stick-from-hilink-to-stick-mode/
system.service.wwan = config.system.callService ./wwan.nix {
apn = mkOption { type = types.str; };
username = mkOption { type = types.str; };
password = mkOption { type = types.str; };
authType = mkOption { type = types.enum [ "pap" "chap" ]; };
};
};
}

View file

@ -1,47 +0,0 @@
{
liminix
, usb-modeswitch
, ppp
, lib
, svc
}:
{ apn, username, password, authType }:
let
inherit (liminix.services) oneshot;
authTypeNum = if authType == "pap" then "1" else "2";
chat = lib.escapeShellArgs [
# Your usb modem thing might present as a tty that you run PPP
# over, or as a network device ("ndis" or "ncm"). The latter
# kind is to be preferred, at least in principle, because it's
# faster. This initialization sequence works for the Huawei
# E3372, and took much swearing: the error messages are *awful*
"" "AT"
"OK" "ATZ"
# create PDP context
"OK" "AT+CGDCONT=1,\"IP\",\"${apn}\""
# activate PDP context
"OK" "AT+CGACT=1,1"
# setup username and password per requirements of sim provider.
# (caret is special to chat, so needs escaping in AT commands)
"OK" "AT\\^AUTHDATA=1,${authTypeNum},\"\",\"${password}\",\"${username}\""
# start the thing (I am choosing to read this as "NDIS DialUP")
"OK" "AT\\^NDISDUP=1,1"
];
modemConfig = oneshot {
name = "modem-configure";
# this is currently only going to work if there is one
# modem only plugged in, it is plugged in already at boot,
# and nothing else is providing a USB tty.
# https://stackoverflow.com/questions/5477882/how-to-i-detect-whether-a-tty-belonging-to-a-gsm-3g-modem-is-a-data-or-control-p
up = ''
sleep 2
${usb-modeswitch}/bin/usb_modeswitch -v 12d1 -p 14fe --huawei-new-mode
sleep 5
${ppp}/bin/chat -s -v ${chat} 0<>/dev/ttyUSB0 1>&0
'';
down = "chat -v '' ATZ OK </dev/ttyUSB0 >&0";
};
in svc.network.link.build {
ifname = "wwan0";
dependencies = [ modemConfig ];
}

View file

@ -82,18 +82,6 @@ in {
type = types.str; type = types.str;
example = "/dev/mtdblock3"; example = "/dev/mtdblock3";
}; };
alternativeRootDevice = mkOption {
description = "Full path to alternative preferred root device (the B partition of your rootfs)";
type = types.nullOr types.str;
example = "ubi_b:rootfs";
default = null;
};
ubi.mtds = mkOption {
description = "List of MTD device to attach";
type = types.listOf types.str;
example = [ "ubi_a" "ubi_b" "data" ];
default = [ ];
};
networkInterfaces = mkOption { networkInterfaces = mkOption {
type = types.attrsOf types.anything; type = types.attrsOf types.anything;
}; };

View file

@ -20,30 +20,15 @@ in {
system.service.hostapd = mkOption { system.service.hostapd = mkOption {
type = liminix.lib.types.serviceDefn; type = liminix.lib.types.serviceDefn;
}; };
system.service.hostapd-ready = mkOption {
type = liminix.lib.types.serviceDefn;
};
}; };
config = { config = {
system.service.hostapd = liminix.callService ./service.nix { system.service.hostapd = liminix.callService ./service.nix {
interface = mkOption { interface = mkOption {
type = liminix.lib.types.service; type = liminix.lib.types.service;
}; };
package = mkOption {
type = types.package;
default = pkgs.hostapd;
};
params = mkOption { params = mkOption {
type = types.attrs; type = types.attrs;
}; };
}; };
system.service.hostapd-ready = liminix.callService ./ready.nix {
interface = mkOption {
type = liminix.lib.types.interface;
description = "Interface for which to wait that the oper state Master or Master (VLAN) has been reached.";
};
};
}; };
} }

View file

@ -1,16 +0,0 @@
{
liminix
, ifwait
, lib
}:
{ interface } :
let
inherit (liminix.services) oneshot;
in oneshot {
name = "${interface.name}.wlan-oper";
up = ''
${ifwait}/bin/ifbridgeable -v $(output ${interface} ifname)
'';
dependencies = [ interface ];
}

View file

@ -1,9 +1,10 @@
{ {
liminix liminix
, hostapd
, writeText , writeText
, lib , lib
}: }:
{ package, interface, params } : { interface, params} :
let let
inherit (liminix.services) longrun; inherit (liminix.services) longrun;
inherit (lib) concatStringsSep mapAttrsToList; inherit (lib) concatStringsSep mapAttrsToList;
@ -34,5 +35,5 @@ let
in longrun { in longrun {
inherit name; inherit name;
dependencies = [ interface ]; dependencies = [ interface ];
run = "${package}/bin/hostapd -i $(output ${interface} ifname) -P /run/${name}.pid -S ${conf}"; run = "${hostapd}/bin/hostapd -i $(output ${interface} ifname) -P /run/${name}.pid -S ${conf}";
} }

View file

@ -1,6 +1,7 @@
{ lib, pkgs, config, ...}: { lib, pkgs, config, ...}:
let let
inherit (lib) mkOption types; inherit (lib) mkOption types;
inherit (pkgs.liminix.services) oneshot;
in { in {
options = { options = {
hostname = mkOption { hostname = mkOption {
@ -11,21 +12,12 @@ in {
default = "liminix"; default = "liminix";
type = types.nonEmptyStr; type = types.nonEmptyStr;
}; };
hostname-script = mkOption { };
description = '' config = {
Script that outputs the system hostname on stdin. services.hostname = oneshot {
''; name = "hostname";
default = pkgs.writeScript "hostname-gen" '' up = "echo ${config.hostname} > /proc/sys/kernel/hostname";
#!/bin/sh down = "true";
echo ${config.hostname}
'';
defaultText = ''
pkgs.writeScript "hostname-gen" '''
#!/bin/sh
echo ''${config.hostname}
'''
'';
type = types.package;
}; };
}; };
} }

View file

@ -1,21 +0,0 @@
## CPU Jitter RNG
## ==============
##
## CPU Jitter RNG is a random number generator # providing non-physical true
## random generation # that works equally for kernel and user-land. It relies
## on the availability of a high-resolution timer.
{ lib, pkgs, ... }:
let
inherit (lib) mkOption types;
inherit (pkgs) liminix;
in {
options.system.service.jitter-rng = mkOption {
type = liminix.lib.types.serviceDefn;
};
config = {
system.service.jitter-rng = pkgs.liminix.callService ./jitter-rng.nix {
};
};
}

View file

@ -1,18 +0,0 @@
{
liminix
, lib
, jitterentropy-rngd
}:
{ }:
let
inherit (liminix.services) longrun;
name = "jitterentropy-rngd";
in
longrun {
# Does it need to be unique?
inherit name;
run = ''
mkdir -p /run/jitterentropy-rngd
${jitterentropy-rngd}/bin/jitterentropy-rngd -v -p /run/jitterentropy-rngd/${name}.pid
'';
}

View file

@ -1,35 +0,0 @@
# Taken from NixOS.
{ lib, ... }:
with lib;
{
options = {
assertions = mkOption {
type = types.listOf types.unspecified;
internal = true;
default = [];
example = [ { assertion = false; message = "you can't enable this for that reason"; } ];
description = ''
This option allows modules to express conditions that must
hold for the evaluation of the system configuration to
succeed, along with associated error messages for the user.
'';
};
warnings = mkOption {
internal = true;
default = [];
type = types.listOf types.str;
example = [ "The `foo' service is deprecated and will go away soon!" ];
description = ''
This option allows modules to show warnings to users during
the evaluation of the system configuration.
'';
};
};
# impl of assertions is in <nixpkgs/nixos/modules/system/activation/top-level.nix>
}

View file

@ -17,7 +17,7 @@ let
ip address replace $ip/$mask dev $interface ip address replace $ip/$mask dev $interface
(in_outputs ${name} (in_outputs ${name}
for i in lease mask ip router siaddr dns serverid subnet opt53 interface ; do for i in lease mask ip router siaddr dns serverid subnet opt53 interface ; do
(printenv $i || true) > $i printenv $i > $i
done) done)
} }
case $action in case $action in
@ -40,7 +40,7 @@ let
''; '';
in longrun { in longrun {
inherit name; inherit name;
run = "exec /bin/udhcpc -f -i $(output ${interface} ifname) -x hostname:$(cat /proc/sys/kernel/hostname) -s ${script}"; run = "/bin/udhcpc -f -i $(output ${interface} ifname) -x hostname:$(cat /proc/sys/kernel/hostname) -s ${script}";
notification-fd = 10; notification-fd = 10;
dependencies = [ interface ]; dependencies = [ interface ];
} }

View file

@ -1,402 +0,0 @@
{ config, options, lib, pkgs, ... }:
with lib;
let
cfg = config.nixpkgs;
opt = options.nixpkgs;
isConfig = x:
builtins.isAttrs x || lib.isFunction x;
optCall = f: x:
if lib.isFunction f
then f x
else f;
mergeConfig = lhs_: rhs_:
let
lhs = optCall lhs_ { inherit pkgs; };
rhs = optCall rhs_ { inherit pkgs; };
in
recursiveUpdate lhs rhs //
optionalAttrs (lhs ? packageOverrides) {
packageOverrides = pkgs:
optCall lhs.packageOverrides pkgs //
optCall (attrByPath [ "packageOverrides" ] { } rhs) pkgs;
} //
optionalAttrs (lhs ? perlPackageOverrides) {
perlPackageOverrides = pkgs:
optCall lhs.perlPackageOverrides pkgs //
optCall (attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
};
configType = mkOptionType {
name = "nixpkgs-config";
description = "nixpkgs config";
check = x:
let traceXIfNot = c:
if c x then true
else lib.traceSeqN 1 x false;
in traceXIfNot isConfig;
merge = args: foldr (def: mergeConfig def.value) {};
};
overlayType = mkOptionType {
name = "nixpkgs-overlay";
description = "nixpkgs overlay";
check = lib.isFunction;
merge = lib.mergeOneOption;
};
pkgsType = types.pkgs // {
# This type is only used by itself, so let's elaborate the description a bit
# for the purpose of documentation.
description = "An evaluation of Nixpkgs; the top level attribute set of packages";
};
hasBuildPlatform = opt.buildPlatform.highestPrio < (mkOptionDefault {}).priority;
hasHostPlatform = opt.hostPlatform.isDefined;
hasPlatform = hasHostPlatform || hasBuildPlatform;
# Context for messages
hostPlatformLine = optionalString hasHostPlatform "${showOptionWithDefLocs opt.hostPlatform}";
buildPlatformLine = optionalString hasBuildPlatform "${showOptionWithDefLocs opt.buildPlatform}";
legacyOptionsDefined =
optional (opt.localSystem.highestPrio < (mkDefault {}).priority) opt.system
++ optional (opt.localSystem.highestPrio < (mkOptionDefault {}).priority) opt.localSystem
++ optional (opt.crossSystem.highestPrio < (mkOptionDefault {}).priority) opt.crossSystem
;
defaultPkgs =
if opt.hostPlatform.isDefined
then
let isCross = cfg.buildPlatform != cfg.hostPlatform;
systemArgs =
if isCross
then {
localSystem = cfg.buildPlatform;
crossSystem = cfg.hostPlatform;
}
else {
localSystem = cfg.hostPlatform;
};
in
import cfg.source ({
inherit (cfg) config overlays;
} // systemArgs)
else
import cfg.source {
inherit (cfg) config overlays localSystem crossSystem;
};
finalPkgs = if opt.pkgs.isDefined then cfg.pkgs.appendOverlays cfg.overlays else defaultPkgs;
in
{
options.nixpkgs = {
source = mkOption {
type = types.package // {
description = "Source of a nixpkgs repository";
};
default = <nixpkgs>;
defaultText = "<nixpkgs>";
};
pkgs = mkOption {
defaultText = literalExpression ''
import "''${nixos}/.." {
inherit (cfg) config overlays localSystem crossSystem;
}
'';
type = pkgsType;
example = literalExpression "import <nixpkgs> {}";
description = ''
If set, the pkgs argument to all NixOS modules is the value of
this option, extended with `nixpkgs.overlays`, if
that is also set. Either `nixpkgs.crossSystem` or
`nixpkgs.localSystem` will be used in an assertion
to check that the NixOS and Nixpkgs architectures match. Any
other options in `nixpkgs.*`, notably `config`,
will be ignored.
If unset, the pkgs argument to all NixOS modules is determined
as shown in the default value for this option.
The default value imports the Nixpkgs source files
relative to the location of this NixOS module, because
NixOS and Nixpkgs are distributed together for consistency,
so the `nixos` in the default value is in fact a
relative path. The `config`, `overlays`,
`localSystem`, and `crossSystem` come
from this option's siblings.
This option can be used by applications like NixOps to increase
the performance of evaluation, or to create packages that depend
on a container that should be built with the exact same evaluation
of Nixpkgs, for example. Applications like this should set
their default value using `lib.mkDefault`, so
user-provided configuration can override it without using
`lib`.
Note that using a distinct version of Nixpkgs with NixOS may
be an unexpected source of problems. Use this option with care.
'';
};
config = mkOption {
default = {};
example = literalExpression
''
{ allowBroken = true; allowUnfree = true; }
'';
type = configType;
description = ''
Global configuration for Nixpkgs.
The complete list of [Nixpkgs configuration options](https://nixos.org/manual/nixpkgs/unstable/#sec-config-options-reference) is in the [Nixpkgs manual section on global configuration](https://nixos.org/manual/nixpkgs/unstable/#chap-packageconfig).
Ignored when {option}`nixpkgs.pkgs` is set.
'';
};
overlays = mkOption {
default = [];
example = literalExpression
''
[
(self: super: {
openssh = super.openssh.override {
hpnSupport = true;
kerberos = self.libkrb5;
};
})
]
'';
type = types.listOf overlayType;
description = ''
List of overlays to apply to Nixpkgs.
This option allows modifying the Nixpkgs package set accessed through the `pkgs` module argument.
For details, see the [Overlays chapter in the Nixpkgs manual](https://nixos.org/manual/nixpkgs/stable/#chap-overlays).
If the {option}`nixpkgs.pkgs` option is set, overlays specified using `nixpkgs.overlays` will be applied after the overlays that were already included in `nixpkgs.pkgs`.
'';
};
hostPlatform = mkOption {
type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform
example = { system = "aarch64-linux"; };
# Make sure that the final value has all fields for sake of other modules
# referring to this. TODO make `lib.systems` itself use the module system.
apply = lib.systems.elaborate;
defaultText = literalExpression
''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform'';
description = ''
Specifies the platform where the NixOS configuration will run.
To cross-compile, set also `nixpkgs.buildPlatform`.
Ignored when `nixpkgs.pkgs` is set.
'';
};
buildPlatform = mkOption {
type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform
default = cfg.hostPlatform;
example = { system = "x86_64-linux"; };
# Make sure that the final value has all fields for sake of other modules
# referring to this.
apply = inputBuildPlatform:
let elaborated = lib.systems.elaborate inputBuildPlatform;
in if lib.systems.equals elaborated cfg.hostPlatform
then cfg.hostPlatform # make identical, so that `==` equality works; see https://github.com/NixOS/nixpkgs/issues/278001
else elaborated;
defaultText = literalExpression
''config.nixpkgs.hostPlatform'';
description = ''
Specifies the platform on which NixOS should be built.
By default, NixOS is built on the system where it runs, but you can
change where it's built. Setting this option will cause NixOS to be
cross-compiled.
For instance, if you're doing distributed multi-platform deployment,
or if you're building machines, you can set this to match your
development system and/or build farm.
Ignored when `nixpkgs.pkgs` is set.
'';
};
localSystem = mkOption {
type = types.attrs; # TODO utilize lib.systems.parsedPlatform
default = { inherit (cfg) system; };
example = { system = "aarch64-linux"; };
# Make sure that the final value has all fields for sake of other modules
# referring to this. TODO make `lib.systems` itself use the module system.
apply = lib.systems.elaborate;
defaultText = literalExpression
''(import "''${nixos}/../lib").lib.systems.examples.aarch64-multiplatform'';
description = ''
Systems with a recently generated `hardware-configuration.nix`
do not need to specify this option, unless cross-compiling, in which case
you should set *only* {option}`nixpkgs.buildPlatform`.
If this is somehow not feasible, you may fall back to removing the
{option}`nixpkgs.hostPlatform` line from the generated config and
use the old options.
Specifies the platform on which NixOS should be built. When
`nixpkgs.crossSystem` is unset, it also specifies
the platform *for* which NixOS should be
built. If this option is unset, it defaults to the platform
type of the machine where evaluation happens. Specifying this
option is useful when doing distributed multi-platform
deployment, or when building virtual machines. See its
description in the Nixpkgs manual for more details.
Ignored when `nixpkgs.pkgs` or `hostPlatform` is set.
'';
};
# TODO deprecate. "crossSystem" is a nonsense identifier, because "cross"
# is a relation between at least 2 systems in the context of a
# specific build step, not a single system.
crossSystem = mkOption {
type = types.nullOr types.attrs; # TODO utilize lib.systems.parsedPlatform
default = null;
example = { system = "aarch64-linux"; };
description = ''
Systems with a recently generated `hardware-configuration.nix`
may instead specify *only* {option}`nixpkgs.buildPlatform`,
or fall back to removing the {option}`nixpkgs.hostPlatform` line from the generated config.
Specifies the platform for which NixOS should be
built. Specify this only if it is different from
`nixpkgs.localSystem`, the platform
*on* which NixOS should be built. In other
words, specify this to cross-compile NixOS. Otherwise it
should be set as null, the default. See its description in the
Nixpkgs manual for more details.
Ignored when `nixpkgs.pkgs` or `hostPlatform` is set.
'';
};
system = mkOption {
type = types.str;
example = "i686-linux";
default =
if opt.hostPlatform.isDefined
then
throw ''
Neither ${opt.system} nor any other option in nixpkgs.* is meant
to be read by modules and configurations.
Use pkgs.stdenv.hostPlatform instead.
''
else
throw ''
Neither ${opt.hostPlatform} nor the legacy option ${opt.system} has been set.
You can set ${opt.hostPlatform} in hardware-configuration.nix by re-running
a recent version of nixos-generate-config.
The option ${opt.system} is still fully supported for NixOS 22.05 interoperability,
but will be deprecated in the future, so we recommend to set ${opt.hostPlatform}.
'';
defaultText = lib.literalMD ''
Traditionally `builtins.currentSystem`, but unset when invoking NixOS through `lib.nixosSystem`.
'';
description = ''
This option does not need to be specified for NixOS configurations
with a recently generated `hardware-configuration.nix`.
Specifies the Nix platform type on which NixOS should be built.
It is better to specify `nixpkgs.localSystem` instead.
```
{
nixpkgs.system = ..;
}
```
is the same as
```
{
nixpkgs.localSystem.system = ..;
}
```
See `nixpkgs.localSystem` for more information.
Ignored when `nixpkgs.pkgs`, `nixpkgs.localSystem` or `nixpkgs.hostPlatform` is set.
'';
};
};
config = {
_module.args = {
pkgs =
# We explicitly set the default override priority, so that we do not need
# to evaluate finalPkgs in case an override is placed on `_module.args.pkgs`.
# After all, to determine a definition priority, we need to evaluate `._type`,
# which is somewhat costly for Nixpkgs. With an explicit priority, we only
# evaluate the wrapper to find out that the priority is lower, and then we
# don't need to evaluate `finalPkgs`.
lib.mkOverride lib.modules.defaultOverridePriority
finalPkgs.__splicedPackages;
lim = lib.mkOverride lib.modules.defaultOverridePriority
finalPkgs.__splicedPackages.lim;
};
assertions = let
# Whether `pkgs` was constructed by this module. This is false when any of
# nixpkgs.pkgs or _module.args.pkgs is set.
constructedByMe =
# We set it with default priority and it can not be merged, so if the
# pkgs module argument has that priority, it's from us.
(lib.modules.mergeAttrDefinitionsWithPrio options._module.args).pkgs.highestPrio
== lib.modules.defaultOverridePriority
# Although, if nixpkgs.pkgs is set, we did forward it, but we did not construct it.
&& !opt.pkgs.isDefined;
in [
(
let
nixosExpectedSystem =
if config.nixpkgs.crossSystem != null
then config.nixpkgs.crossSystem.system or (lib.systems.parse.doubleFromSystem (lib.systems.parse.mkSystemFromString config.nixpkgs.crossSystem.config))
else config.nixpkgs.localSystem.system or (lib.systems.parse.doubleFromSystem (lib.systems.parse.mkSystemFromString config.nixpkgs.localSystem.config));
nixosOption =
if config.nixpkgs.crossSystem != null
then "nixpkgs.crossSystem"
else "nixpkgs.localSystem";
pkgsSystem = finalPkgs.stdenv.targetPlatform.system;
in {
assertion = constructedByMe -> !hasPlatform -> nixosExpectedSystem == pkgsSystem;
message = "The NixOS nixpkgs.pkgs option was set to a Nixpkgs invocation that compiles to target system ${pkgsSystem} but NixOS was configured for system ${nixosExpectedSystem} via NixOS option ${nixosOption}. The NixOS system settings must match the Nixpkgs target system.";
}
)
{
assertion = constructedByMe -> hasPlatform -> legacyOptionsDefined == [];
message = ''
Your system configures nixpkgs with the platform parameter${optionalString hasBuildPlatform "s"}:
${hostPlatformLine
}${buildPlatformLine
}
However, it also defines the legacy options:
${concatMapStrings showOptionWithDefLocs legacyOptionsDefined}
For a future proof system configuration, we recommend to remove
the legacy definitions.
'';
}
{
assertion = opt.pkgs.isDefined -> cfg.config == {};
message = ''
Your system configures nixpkgs with an externally created instance.
`nixpkgs.config` options should be passed when creating the instance instead.
Current value:
${lib.generators.toPretty { multiline = true; } opt.config}
'';
}
];
};
}

View file

@ -5,15 +5,9 @@
, ... , ...
}: }:
let let
inherit (lib) mkOption types concatStringsSep filter; inherit (lib) mkOption types concatStringsSep;
inherit (pkgs) liminix callPackage writeText; inherit (pkgs) liminix callPackage writeText;
o = config.system.outputs; o = config.system.outputs;
# Handle assertions and warnings
failedAssertions = map (x: x.message) (filter (x: !x.assertion) config.assertions);
baseSystemConfiguration = if failedAssertions != []
then throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}"
else lib.showWarnings config.warnings o.systemConfiguration;
in in
{ {
imports = [ imports = [
@ -127,10 +121,10 @@ in
inherit (pkgs.pkgsBuildBuild) runCommand; inherit (pkgs.pkgsBuildBuild) runCommand;
in runCommand "mktree" { } '' in runCommand "mktree" { } ''
mkdir -p $out/nix/store/ $out/secrets $out/boot mkdir -p $out/nix/store/ $out/secrets $out/boot
cp ${baseSystemConfiguration}/bin/activate $out/activate cp ${o.systemConfiguration}/bin/activate $out/activate
ln -s ${pkgs.s6-init-bin}/bin/init $out/init ln -s ${pkgs.s6-init-bin}/bin/init $out/init
mkdir -p $out/nix/store mkdir -p $out/nix/store
for path in $(cat ${baseSystemConfiguration}/etc/nix-store-paths) ; do for path in $(cat ${o.systemConfiguration}/etc/nix-store-paths) ; do
(cd $out && cp -a $path .$path) (cd $out && cp -a $path .$path)
done done
''; '';

View file

@ -36,43 +36,22 @@ in
kernel.config = { kernel.config = {
BLK_DEV_INITRD = "y"; BLK_DEV_INITRD = "y";
INITRAMFS_SOURCE = builtins.toJSON "${config.system.outputs.initramfs}"; INITRAMFS_SOURCE = builtins.toJSON "${config.system.outputs.initramfs}";
INITRAMFS_COMPRESSION_ZSTD = "y"; # INITRAMFS_COMPRESSION_LZO = "y";
}; };
system.outputs = { system.outputs = {
initramfs = initramfs =
let let inherit (pkgs.pkgsBuildBuild) gen_init_cpio;
inherit (pkgs.pkgsBuildBuild) gen_init_cpio cpio writeScript;
inherit (pkgs) busybox;
failsafe-init = writeScript "init" ''
#!/bin/sh
exec >/dev/console
echo Running in initramfs
PATH=${busybox}/bin:$PATH
export PATH
mount -t proc none /proc
mount -t sysfs none /sys
${busybox}/bin/sh
'';
refs = pkgs.writeReferencesToFile busybox;
in runCommand "initramfs.cpio" {} '' in runCommand "initramfs.cpio" {} ''
cat << SPECIALS | ${gen_init_cpio}/bin/gen_init_cpio /dev/stdin > out cat << SPECIALS | ${gen_init_cpio}/bin/gen_init_cpio /dev/stdin > $out
dir /proc 0755 0 0 dir /proc 0755 0 0
dir /dev 0755 0 0 dir /dev 0755 0 0
nod /dev/console 0600 0 0 c 5 1 nod /dev/console 0600 0 0 c 5 1
dir /target 0755 0 0 dir /target 0755 0 0
dir /target/persist 0755 0 0 dir /target/persist 0755 0 0
dir /target/nix 0755 0 0 dir /target/nix 0755 0 0
dir /nix 0755 0 0
dir /nix/store 0755 0 0
dir /bin 0755 0 0
file /bin/sh ${busybox}/bin/sh 0755 0 0
file /init ${pkgs.preinit}/bin/preinit 0755 0 0 file /init ${pkgs.preinit}/bin/preinit 0755 0 0
file /failsafe-init ${failsafe-init} 0755 0 0
SPECIALS SPECIALS
find $(cat ${refs}) | ${cpio}/bin/cpio -H newc -o -A -v -O out
mv out $out
''; '';
systemConfiguration = systemConfiguration =
pkgs.systemconfig config.filesystem.contents; pkgs.systemconfig config.filesystem.contents;

View file

@ -5,8 +5,7 @@
, ... , ...
}: }:
let let
inherit (pkgs) liminix; inherit (lib) mkIf mkOption types;
inherit (lib) mkIf;
o = config.system.outputs; o = config.system.outputs;
in in
{ {
@ -25,10 +24,17 @@ in
}; };
boot.initramfs.enable = true; boot.initramfs.enable = true;
system.outputs = { system.outputs = {
rootfs = liminix.builders.jffs2 { rootfs =
bootableRootDirectory = o.bootablerootdir; let
inherit (config.hardware.flash) eraseBlockSize; inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
}; endian = if pkgs.stdenv.isBigEndian
then "--big-endian" else "--little-endian";
in runCommand "make-jffs2" {
depsBuildBuild = [ mtdutils ];
} ''
tree=${o.bootablerootdir}
(cd $tree && mkfs.jffs2 --compression-mode=size ${endian} -e ${toString config.hardware.flash.eraseBlockSize} --enable-compressor=lzo --pad --root . --output $out --squash --faketime )
'';
}; };
}; };
} }

View file

@ -1,14 +0,0 @@
/dts-v1/;
/ {
description = "Liminix TFTP bootscript";
#address-cells = <1>;
images {
bootscript {
description = "Bootscript";
data = /incbin/("boot.scr");
type = "script";
compression = "none";
};
};

View file

@ -5,23 +5,10 @@
, ... , ...
}: }:
let let
inherit (lib) mkOption mkIf types concatStringsSep; inherit (lib) mkOption types concatStringsSep;
inherit (pkgs) liminix;
cfg = config.boot.tftp; cfg = config.boot.tftp;
hw = config.hardware; hw = config.hardware;
arch = pkgs.stdenv.hostPlatform.linuxArch; arch = pkgs.stdenv.hostPlatform.linuxArch;
# UBI cannot run on the top of phram.
needsJffs2 = config.rootfsType == "ubifs";
# squashfs doesn't work out for us because only `bootablerootdir`
# contain what we need to boot, not `config.filesystem.contents` alas.
rootfstype = if needsJffs2 then "jffs2" else config.rootfsType;
rootfs = if needsJffs2 then
liminix.builders.jffs2 {
bootableRootDirectory = config.system.outputs.bootablerootdir;
inherit (config.hardware.flash) eraseBlockSize;
}
else config.system.outputs.rootfs;
in { in {
imports = [ ../ramdisk.nix ]; imports = [ ../ramdisk.nix ];
options.boot.tftp = { options.boot.tftp = {
@ -64,56 +51,11 @@ in {
It uses the Linux `phram <https://github.com/torvalds/linux/blob/master/drivers/mtd/devices/phram.c>`_ driver to emulate a flash device using a segment of physical RAM. It uses the Linux `phram <https://github.com/torvalds/linux/blob/master/drivers/mtd/devices/phram.c>`_ driver to emulate a flash device using a segment of physical RAM.
''; '';
}; };
tftpboot-fit = mkOption {
type = types.package;
description = ''
tftpboot-fit
************
This output is a variant that encloses the `boot.scr` in a FIT
if that's simpler to transfer for you.
'';
};
}; };
config = { config = {
boot.ramdisk.enable = true; boot.ramdisk.enable = true;
kernel.config = mkIf needsJffs2 {
JFFS2_FS = "y";
JFFS2_LZO = "y";
JFFS2_RTIME = "y";
JFFS2_COMPRESSION_OPTIONS = "y";
JFFS2_ZLIB = "y";
JFFS2_CMODE_SIZE = "y";
};
system.outputs = rec { system.outputs = rec {
tftpboot-fit =
let
tftpboot-fit = pkgs.writeText "tftpboot.its" ''
/dts-v1/;
/ {
description = "Liminix TFTP bootscript";
#address-cells = <1>;
images {
bootscript {
description = "Bootscript";
data = /incbin/("${tftpboot}/boot.scr");
type = "script";
compression = "none";
};
};
};
'';
in
pkgs.runCommand "tftpboot-fit" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ ubootTools ]; } ''
mkdir -p $out/
cp -rf ${tftpboot}/* $out/
mkimage -f ${tftpboot-fit} $out/script.ub
'';
tftpboot = tftpboot =
let let
inherit (pkgs.lib.trivial) toHexString; inherit (pkgs.lib.trivial) toHexString;
@ -127,7 +69,7 @@ in {
zimage = "bootz"; zimage = "bootz";
}; in choices.${cfg.kernelFormat}; }; in choices.${cfg.kernelFormat};
cmdline = concatStringsSep " " config.boot.tftp.commandLine; cmdline = concatStringsSep " " config.boot.commandLine;
objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy"; objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy";
stripAndZip = '' stripAndZip = ''
${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin ${objcopy} -O binary -R .reginfo -R .notes -R .note -R .comment -R .mdebug -R .note.gnu.build-id -S vmlinux.elf vmlinux.bin
@ -142,7 +84,7 @@ in {
hex() { printf "0x%x" $1; } hex() { printf "0x%x" $1; }
rootfsStart=${toString cfg.loadAddress} rootfsStart=${toString cfg.loadAddress}
rootfsSize=$(binsize64k ${rootfs} ) rootfsSize=$(binsize64k ${o.rootfs} )
rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} )) rootfsSize=$(($rootfsSize + ${toString cfg.freeSpaceBytes} ))
ln -s ${o.manifest} manifest ln -s ${o.manifest} manifest
@ -156,13 +98,13 @@ in {
dtbStart=$(($rootfsStart + $rootfsSize)) dtbStart=$(($rootfsStart + $rootfsSize))
${if cfg.compressRoot ${if cfg.compressRoot
then '' then ''
lzma -z9cv ${rootfs} > rootfs.lz lzma -z9cv ${o.rootfs} > rootfs.lz
rootfsLzStart=$dtbStart rootfsLzStart=$dtbStart
rootfsLzSize=$(binsize rootfs.lz) rootfsLzSize=$(binsize rootfs.lz)
dtbStart=$(($dtbStart + $rootfsLzSize)) dtbStart=$(($dtbStart + $rootfsLzSize))
'' ''
else '' else ''
ln -s ${rootfs} rootfs ln -s ${o.rootfs} rootfs
'' ''
} }
@ -179,7 +121,7 @@ in {
fdtput -p -t s dtb /reserved-memory/$node compatible phram fdtput -p -t s dtb /reserved-memory/$node compatible phram
fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize) fdtput -p -t lx dtb /reserved-memory/$node reg $ac_prefix $(hex $rootfsStart) $sz_prefix $(hex $rootfsSize)
cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} rootfstype=${rootfstype} root=/dev/mtdblock0"; cmd="liminix ${cmdline} mtdparts=phram0:''${rootfsSize}(rootfs) phram.phram=phram0,''${rootfsStart},''${rootfsSize},${toString config.hardware.flash.eraseBlockSize} root=/dev/mtdblock0";
fdtput -t s dtb /chosen ${config.boot.commandLineDtbNode} "$cmd" fdtput -t s dtb /chosen ${config.boot.commandLineDtbNode} "$cmd"
dtbSize=$(binsize ./dtb ) dtbSize=$(binsize ./dtb )

View file

@ -63,7 +63,7 @@ in
ln -s ${kernel.headers} build ln -s ${kernel.headers} build
echo ${cmdline} > commandline echo ${cmdline} > commandline
cat > run.sh << EOF cat > run.sh << EOF
#!${pkgs.pkgsBuildBuild.runtimeShell} #!${pkgs.runtimeShell}
${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --command-line ${cmdline} --arch ${pkgs.stdenv.hostPlatform.qemuArch} --phram-address 0x${phram_address} \$* ${makeBootableImage} ${config.system.outputs.rootfs} ${pkgs.pkgsBuildBuild.run-liminix-vm}/bin/run-liminix-vm --command-line ${cmdline} --arch ${pkgs.stdenv.hostPlatform.qemuArch} --phram-address 0x${phram_address} \$* ${makeBootableImage} ${config.system.outputs.rootfs}
EOF EOF
chmod +x run.sh chmod +x run.sh

View file

@ -62,7 +62,7 @@ on a system with pre-existing firmware and OS.
}; };
''; '';
in in
pkgs.runCommand "zyxel-nwa-fit" { pkgs.runCommand "zyxel-nwa-fit-${config.boot.imageType}" {
nativeBuildInputs = [ pkgs.pkgsBuildBuild.ubootTools pkgs.pkgsBuildBuild.dtc ]; nativeBuildInputs = [ pkgs.pkgsBuildBuild.ubootTools pkgs.pkgsBuildBuild.dtc ];
} '' } ''
mkimage -f ${dts} $out mkimage -f ${dts} $out

View file

@ -1,83 +0,0 @@
{ config, lib, pkgs, ... }:
# Inspired from nixpkgs/NixOS.
with lib;
let
inherit (pkgs.pseudofile) dir symlink;
cfg = config.security.pki;
cacertPackage = pkgs.cacert.override {
blacklist = [ ];
extraCertificateFiles = cfg.certificateFiles;
extraCertificateStrings = cfg.certificates;
};
caBundleName = "ca-bundle.crt";
caBundle = "${cacertPackage}/etc/ssl/certs/${caBundleName}";
in
{
options = {
security.pki.installCACerts = mkEnableOption "installing CA certificates to the system" // {
default = false;
};
security.pki.certificateFiles = mkOption {
type = types.listOf types.path;
default = [];
example = literalExpression ''[ "''${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ]'';
description = ''
A list of files containing trusted root certificates in PEM
format. These are concatenated to form
{file}`/etc/ssl/certs/ca-certificates.crt`, which is
used by many programs that use OpenSSL, such as
{command}`curl` and {command}`git`.
'';
};
security.pki.certificates = mkOption {
type = types.listOf types.str;
default = [];
example = literalExpression ''
[ '''
NixOS.org
=========
-----BEGIN CERTIFICATE-----
MIIGUDCCBTigAwIBAgIDD8KWMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
...
-----END CERTIFICATE-----
'''
]
'';
description = ''
A list of trusted root certificates in PEM format.
'';
};
};
config = mkIf cfg.installCACerts {
# NixOS canonical location + Debian/Ubuntu/Arch/Gentoo compatibility.
filesystem = dir {
etc = dir {
ssl = dir {
certs = dir {
"ca-certificates.crt" = symlink caBundle;
"ca-bundle.crt" = symlink caBundle;
};
};
# CentOS/Fedora compatibility.
pki = dir {
certs = dir {
"ca-bundle.crt" = symlink caBundle;
};
};
};
};
};
}

View file

@ -17,9 +17,6 @@ in {
system.service.pppoe = mkOption { system.service.pppoe = mkOption {
type = liminix.lib.types.serviceDefn; type = liminix.lib.types.serviceDefn;
}; };
system.service.l2tp = mkOption {
type = liminix.lib.types.serviceDefn;
};
}; };
config = { config = {
system.service.pppoe = pkgs.liminix.callService ./pppoe.nix { system.service.pppoe = pkgs.liminix.callService ./pppoe.nix {
@ -32,16 +29,6 @@ in {
description = "options supplied on ppp command line"; description = "options supplied on ppp command line";
}; };
}; };
system.service.l2tp = pkgs.liminix.callService ./l2tp.nix {
lns = mkOption {
type = types.str;
description = "hostname or address of the L2TP network server";
};
ppp-options = mkOption {
type = types.listOf types.str;
description = "options supplied on ppp command line";
};
};
kernel = { kernel = {
config = { config = {
PPP = "y"; PPP = "y";
@ -49,8 +36,6 @@ in {
PPP_DEFLATE = "y"; PPP_DEFLATE = "y";
PPP_ASYNC = "y"; PPP_ASYNC = "y";
PPP_SYNC_TTY = "y"; PPP_SYNC_TTY = "y";
PPPOL2TP = "y";
L2TP = "y";
}; };
}; };
}; };

View file

@ -1,62 +0,0 @@
{
liminix
, lib
, ppp
, pppoe
, writeAshScript
, writeText
, serviceFns
, xl2tpd
} :
{ lns, ppp-options }:
let
inherit (liminix.services) longrun;
name = "${lns}.l2tp";
ip-up = writeAshScript "ip-up" {} ''
. ${serviceFns}
(in_outputs ${name}
echo $1 > ifname
echo $2 > tty
echo $3 > speed
echo $4 > address
echo $5 > peer-address
echo $DNS1 > ns1
echo $DNS2 > ns2
)
echo >/proc/self/fd/10
'';
ip6-up = writeAshScript "ip6-up" {} ''
. ${serviceFns}
(in_outputs ${name}
echo $4 > ipv6-address
echo $5 > ipv6-peer-address
)
echo >/proc/self/fd/10
'';
ppp-options' = ppp-options ++ [
"ip-up-script" ip-up
"ipv6-up-script" ip6-up
"ipparam" name
"nodetach"
"usepeerdns"
"logfd" "2"
];
conf = writeText "xl2tpd.conf" ''
[lac upstream]
lns = ${lns}
require authentication = no
pppoptfile = ${writeText "ppp-options" ppp-options'}
autodial = yes
redial = yes
'';
control = "/run/xl2tpd/control-${name}";
in
longrun {
inherit name;
run = ''
mkdir -p /run/xl2tpd
touch ${control}
exec ${xl2tpd}/bin/xl2tpd -D -p /run/xl2tpd/${name}.pid -c ${conf} -C ${control}
'';
notification-fd = 10;
}

View file

@ -30,8 +30,6 @@ let
installPhase = '' installPhase = ''
mkdir $out mkdir $out
cp -r $src $out/scripts cp -r $src $out/scripts
substituteInPlace $out/scripts/rc.init \
--replace-fail 'config.hostname' "${config.hostname-script}"
chmod -R +w $out chmod -R +w $out
''; '';
}; };

View file

@ -36,7 +36,6 @@ fi
### (replace /run/service with your scandir) ### (replace /run/service with your scandir)
s6-rc-init -d -c /etc/s6-rc/compiled /run/service s6-rc-init -d -c /etc/s6-rc/compiled /run/service
config.hostname > /proc/sys/kernel/hostname
### 2. Starting the wanted set of services ### 2. Starting the wanted set of services
### This is also called every time you change runlevels with telinit. ### This is also called every time you change runlevels with telinit.

View file

@ -1,24 +0,0 @@
## ubus
## ====
##
## ubus is a micro-bus à la D-Bus for all your needs.
{ lib, pkgs, config, ...}:
let
inherit (lib) mkOption types;
inherit (pkgs) liminix;
in {
options = {
system.service.ubus = mkOption {
type = liminix.lib.types.serviceDefn;
};
};
config = {
system.service.ubus = liminix.callService ./service.nix {
package = mkOption {
type = types.package;
default = pkgs.ubus;
};
};
};
}

View file

@ -1,16 +0,0 @@
{
liminix
, writeText
, lib
}:
{ package } :
let
inherit (liminix.services) longrun;
in longrun {
# Long term: make it unique so that user can spawn multiple buses if they want.
name = "ubus";
run = ''
mkdir -p /run/ubus
${package}/bin/ubusd -s /run/ubus/ubus.sock
'';
}

View file

@ -1,24 +1,22 @@
final: prev: final: prev:
let let
isCross = final.stdenv.buildPlatform != final.stdenv.hostPlatform;
crossOnly = pkg : amendFn : if isCross then (amendFn pkg) else pkg;
extraPkgs = import ./pkgs/default.nix { extraPkgs = import ./pkgs/default.nix {
inherit (final) lib callPackage; inherit (final) lib callPackage;
}; };
inherit (final) fetchpatch; inherit (final) fetchpatch;
luaHost = prev.lua5_3.overrideAttrs(o: { lua_no_readline = prev.lua5_3.overrideAttrs(o: {
name = "lua-tty"; name = "lua-tty";
preBuild = '' preBuild = ''
makeFlagsArray+=(PLAT="posix" SYSLIBS="-Wl,-E -ldl" CFLAGS="-O2 -fPIC -DLUA_USE_POSIX -DLUA_USE_DLOPEN") makeFlagsArray+=(PLAT="posix" SYSLIBS="-Wl,-E -ldl" CFLAGS="-O2 -fPIC -DLUA_USE_POSIX -DLUA_USE_DLOPEN")
''; '';
# lua in nixpkgs has a postInstall stanza that assumes only # lua in nixpkgs has a postInstall stanza that assumes only
# one output, we need to override that if we're going to # one output, we need to override that if we're going to
# convert to multi-output # convert to multi-output
# outputs = ["bin" "man" "out"]; # outputs = ["bin" "man" "out"];
makeFlags = makeFlags =
builtins.filter (x: (builtins.match "(PLAT|MYLIBS).*" x) == null) builtins.filter (x: (builtins.match "(PLAT|MYLIBS).*" x) == null)
o.makeFlags; o.makeFlags;
}); });
s6 = prev.s6.overrideAttrs(o: s6 = prev.s6.overrideAttrs(o:
let let
@ -43,6 +41,7 @@ let
(if o ? patches then o.patches else []) ++ (if o ? patches then o.patches else []) ++
(if patch_needed then [ patch ] else []); (if patch_needed then [ patch ] else []);
}); });
lua = let s = lua_no_readline.override { self = s; }; in s;
in in
extraPkgs // { extraPkgs // {
# liminix library functions # liminix library functions
@ -130,18 +129,9 @@ extraPkgs // {
"CONFIG_LIBNL32=y" "CONFIG_LIBNL32=y"
"CONFIG_PKCS12=y" "CONFIG_PKCS12=y"
"CONFIG_RSN_PREAUTH=y" "CONFIG_RSN_PREAUTH=y"
"CONFIG_UBUS=y"
"CONFIG_TLS=internal" "CONFIG_TLS=internal"
]; ];
h = prev.hostapd.overrideAttrs(o: { h = prev.hostapd.overrideAttrs(o: {
buildInputs = o.buildInputs ++ [ final.libubox final.ubus ];
src = final.fetchFromGitea {
domain = "git.dgnum.eu";
owner = "DGNum";
repo = "hostapd";
rev = "hostap-liminix-integration";
hash = "sha256-5Xi90keCHxvuKR5Q7STuZDzuM9h9ac6aWoXVQYvqkQI=";
};
extraConfig = ""; extraConfig = "";
configurePhase = '' configurePhase = ''
cat > hostapd/defconfig <<EOF cat > hostapd/defconfig <<EOF
@ -152,54 +142,6 @@ extraPkgs // {
}); });
in h.override { openssl = null; sqlite = null; }; in h.override { openssl = null; sqlite = null; };
hostapd-radius =
let
config = [
"CONFIG_DRIVER_NL80211=y"
"CONFIG_DRIVER_WIRED=y"
"CONFIG_EAP=y"
"CONFIG_EAP_PEAP=y"
"CONFIG_RADIUS_SERVER=y"
"CONFIG_FULL_DYNAMIC_VLAN=y"
"CONFIG_IAPP=y"
"CONFIG_IEEE80211AC=y"
"CONFIG_IEEE80211AX=y"
"CONFIG_IEEE80211N=y"
"CONFIG_IEEE80211W=y"
"CONFIG_INTERNAL_LIBTOMMATH=y"
"CONFIG_INTERNAL_LIBTOMMATH_FAST=y"
"CONFIG_IPV6=y"
"CONFIG_LIBNL32=y"
"CONFIG_PKCS12=y"
"CONFIG_RSN_PREAUTH=y"
"CONFIG_UBUS=y"
"CONFIG_TLS=internal"
];
h = prev.hostapd.overrideAttrs(o: {
buildInputs = o.buildInputs ++ [ final.libubox final.ubus ];
src = final.fetchFromGitea {
domain = "git.dgnum.eu";
owner = "DGNum";
repo = "hostapd";
rev = "hostap-liminix-integration";
hash = "sha256-5Xi90keCHxvuKR5Q7STuZDzuM9h9ac6aWoXVQYvqkQI=";
};
extraConfig = "";
configurePhase = ''
cat > hostapd/defconfig <<EOF
${builtins.concatStringsSep "\n" config}
EOF
${o.configurePhase}
'';
});
in h.override { openssl = null; sqlite = null; };
wpa_supplicant = prev.wpa_supplicant.override {
dbusSupport = false;
withPcsclite = false;
wpa_supplicant_gui = null;
};
kexec-tools-static = prev.kexec-tools.overrideAttrs(o: { kexec-tools-static = prev.kexec-tools.overrideAttrs(o: {
# For kexecboot we copy kexec into a ramdisk on the system being # For kexecboot we copy kexec into a ramdisk on the system being
# upgraded from. This is more likely to work if kexec is # upgraded from. This is more likely to work if kexec is
@ -218,17 +160,13 @@ extraPkgs // {
]; ];
}); });
lua = crossOnly prev.lua5_3 (_: luaHost); luaFull = prev.lua;
inherit lua;
mtdutils = prev.mtdutils.overrideAttrs(o: { mtdutils = prev.mtdutils.overrideAttrs(o: {
patches = (if o ? patches then o.patches else []) ++ [ patches = (if o ? patches then o.patches else []) ++ [
./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch ./pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch
]; ];
postInstall = ''
# Testing programs which we don't need. We save a lot of space!
rm -rf $out/libexec
'';
}); });
nftables = prev.nftables.overrideAttrs(o: { nftables = prev.nftables.overrideAttrs(o: {
@ -333,8 +271,6 @@ extraPkgs // {
''; '';
}; };
libusb1 = prev.libusb1.override { enableUdev = false; };
util-linux-small = prev.util-linux.override { util-linux-small = prev.util-linux.override {
ncursesSupport = false; ncursesSupport = false;
pamSupport = false; pamSupport = false;

View file

@ -1,5 +1,5 @@
default: wlan.lua fs.lua init.lua nl.lua svc.lua net/constants.lua default: fs.lua init.lua nl.lua svc.lua net/constants.lua
test: test:
ln -s . anoia ln -s . anoia

View file

@ -4,7 +4,6 @@
, linotify , linotify
, lua , lua
, lualinux , lualinux
, iwinfo
, cpio , cpio
}: }:
let pname = "anoia"; let pname = "anoia";
@ -13,7 +12,7 @@ in stdenv.mkDerivation {
version = "0.1"; version = "0.1";
src = ./.; src = ./.;
nativeBuildInputs = [ fennel cpio ]; nativeBuildInputs = [ fennel cpio ];
buildInputs = with lua.pkgs; [ linotify lualinux iwinfo ]; buildInputs = with lua.pkgs; [ linotify lualinux ];
outputs = [ "out" "dev" ]; outputs = [ "out" "dev" ];
doCheck = true; doCheck = true;

View file

@ -1,8 +0,0 @@
(local { : nl80211 } (require :iwinfo))
(fn is-bridgeable [ifname]
(let [mode (nl80211.mode ifname)]
(or (= mode "Master") (= mode "Master (VLAN)"))
))
{ : is-bridgeable }

View file

@ -13,7 +13,6 @@ in {
liminix = { liminix = {
builders = { builders = {
squashfs = callPackage ./liminix-tools/builders/squashfs.nix {}; squashfs = callPackage ./liminix-tools/builders/squashfs.nix {};
jffs2 = callPackage ./liminix-tools/builders/jffs2.nix {};
dtb = callPackage ./kernel/dtb.nix {}; dtb = callPackage ./kernel/dtb.nix {};
uimage = callPackage ./kernel/uimage.nix {}; uimage = callPackage ./kernel/uimage.nix {};
kernel = callPackage ./kernel {}; kernel = callPackage ./kernel {};
@ -110,11 +109,7 @@ in {
swconfig = callPackage ./swconfig {}; swconfig = callPackage ./swconfig {};
systemconfig = callPackage ./systemconfig {}; systemconfig = callPackage ./systemconfig {};
tufted = callPackage ./tufted {}; tufted = callPackage ./tufted {};
libubox = callPackage ./libubox {};
ubus = callPackage ./ubus {};
iwinfo = callPackage ./iwinfo {};
uevent-watch = callPackage ./uevent-watch {}; uevent-watch = callPackage ./uevent-watch {};
usb-modeswitch = callPackage ./usb-modeswitch {};
writeAshScript = callPackage ./write-ash-script {}; writeAshScript = callPackage ./write-ash-script {};
writeFennel = callPackage ./write-fennel {}; writeFennel = callPackage ./write-fennel {};
writeFennelScript = callPackage ./write-fennel-script {}; writeFennelScript = callPackage ./write-fennel-script {};

View file

@ -10,7 +10,6 @@
, linotify , linotify
, anoia , anoia
, netlink-lua , netlink-lua
, iwinfo
, fennel , fennel
}: }:
let packages = [ let packages = [
@ -19,7 +18,7 @@ let packages = [
fennel fennel
lualinux lualinux
netlink-lua netlink-lua
iwinfo lua.pkgs.readline
]; ];
join = ps: builtins.concatStringsSep ";" ps; join = ps: builtins.concatStringsSep ";" ps;
luapath = join (builtins.map (f: luapath = join (builtins.map (f:

View file

@ -1,7 +1,7 @@
{ {
buildGoModule buildGoModule
, fetchFromGitHub , fetchFromGitHub
, ppp , pppBuild
}: }:
buildGoModule rec { buildGoModule rec {
@ -16,7 +16,7 @@ buildGoModule rec {
}; };
patchPhase = '' patchPhase = ''
sed -i.bak -e 's:/usr/sbin/pppd:${ppp}/bin/pppd:' cmd/kl2tpd/pppd.go sed -i.bak -e 's:/usr/sbin/pppd:${pppBuild}/bin/pppd:' cmd/kl2tpd/pppd.go
sed -i.bak -e 's:/usr/sbin/kl2tpd:${placeholder "out"}/bin/kl2tpd:' cmd/kpppoed/l2tpd_kl2tpd.go sed -i.bak -e 's:/usr/sbin/kl2tpd:${placeholder "out"}/bin/kl2tpd:' cmd/kpppoed/l2tpd_kl2tpd.go
grep bin/kl2tp cmd/kpppoed/l2tpd_kl2tpd.go grep bin/kl2tp cmd/kpppoed/l2tpd_kl2tpd.go
''; '';

View file

@ -1,14 +1,11 @@
{ {
lua lua
, netlink-lua , netlink-lua
, lualinux
, iwinfo
, writeFennelScript , writeFennelScript
, runCommand , runCommand
, anoia , anoia
}: }:
runCommand "ifwait" {} '' runCommand "ifwait" {} ''
mkdir -p $out/bin mkdir -p $out/bin
cp -p ${writeFennelScript "ifwait" [ anoia netlink-lua ] ./ifwait.fnl} $out/bin/ifwait cp -p ${writeFennelScript "ifwait" [anoia netlink-lua] ./ifwait.fnl} $out/bin/ifwait
cp -p ${writeFennelScript "ifbridgeable" [ anoia lualinux iwinfo ] ./ifbridgeable.fnl} $out/bin/ifbridgeable
'' ''

View file

@ -1,30 +0,0 @@
(local wlan (require :anoia.wlan))
(local { : assoc } (require :anoia))
(local { : msleep } (require :lualinux))
(fn parse-args [args]
(match args
["-v" & rest] (assoc (parse-args rest) :verbose true)
[linkname] {:link linkname}
_ nil))
(fn run [args poll-fn]
(let [parameters
(assert (parse-args args)
(.. "Usage: ifbridgeable [-v] ifname"))]
(when parameters.verbose
(print (.. "ifbridgeable: waiting for "
parameters.link " to be bridgeable")))
(while (not (poll-fn parameters.link))
(when parameters.verbose
(print (.. "ifbridgeable: waiting for " parameters.link " to be bridgeable")))
(msleep 500)
)
)
)
(when (not (= (. arg 0) "test"))
(run arg wlan.is-bridgeable))
{ : run }

View file

@ -19,11 +19,11 @@
(match v (match v
;; - up: Reflects the administrative state of the interface (IFF_UP) ;; - up: Reflects the administrative state of the interface (IFF_UP)
;; - running: Reflects the operational state (IFF_RUNNING). ;; - running: Reflects the operational state (IFF_RUNNING).
{:event "newlink" :name params.link :up "yes" :running "yes"} {:event "newlink" :name params.link :up :yes :running :yes}
{:present true :up true :running true} {:present true :up true :running true}
{:event "newlink" :name params.link :up "yes"} {:event "newlink" :name params.link :up :yes}
{:present true :up true} {:present :true :up true}
{:event "newlink" :name params.link} {:event "newlink" :name params.link}
{:present true } {:present true }

View file

@ -1,59 +0,0 @@
{
lib,
stdenv,
fetchFromGitea,
ubus,
libubox,
lua5_3,
libnl-tiny,
backend ? "nl80211"
}:
let
lua = lua5_3;
in
stdenv.mkDerivation rec {
pname = "iwinfo";
version = "unstable-07-09-2024";
src = fetchFromGitea {
domain = "git.dgnum.eu";
owner = "DGNum";
repo = "iwinfo";
rev = "14685a26805155aa5c137993b9a4861a0bc585d5";
hash = "sha256-lg4sBoYcFFLhcUv+wKR6u1OCartjtnAoF9M5FdfO6JE=";
};
BACKENDS = backend;
buildInputs = [
ubus
libubox
lua
libnl-tiny
];
CFLAGS = "-I${libnl-tiny}/include/libnl-tiny -D_GNU_SOURCE";
installPhase = ''
runHook preInstall
install -Dm755 iwinfo $out/bin/iwinfo
install -Dm755 iwinfo.so $out/lib/lua/${lua.luaversion}/iwinfo.so
install -Dm755 libiwinfo.so $out/lib/libiwinfo.so
install -Dm755 libiwinfo.so.0 $out/lib/libiwinfo.so.0
mkdir -p $out/include
cp -r include/* $out/include
runHook postInstall
'';
meta = {
description = "Library to access wireless devices";
homepage = "https://github.com/openwrt/iwinfo";
license = lib.licenses.gpl2Only;
maintainers = with lib.maintainers; [ raitobezarius ];
mainProgram = "iwinfo";
platforms = lib.platforms.all;
};
}

View file

@ -23,7 +23,7 @@ stdenv.mkDerivation rec {
nativeBuildInputs = [buildPackages.stdenv.cc] ++ nativeBuildInputs = [buildPackages.stdenv.cc] ++
(with buildPackages.pkgs; [ (with buildPackages.pkgs; [
rsync bc bison flex pkg-config rsync bc bison flex pkg-config
openssl ncurses.all perl zstd openssl ncurses.all perl
]); ]);
CC = "${stdenv.cc.bintools.targetPrefix}gcc"; CC = "${stdenv.cc.bintools.targetPrefix}gcc";
HOSTCC = with buildPackages.pkgs; HOSTCC = with buildPackages.pkgs;

View file

@ -1,49 +0,0 @@
{
lib,
stdenv,
fetchFromGitea,
cmake,
lua,
json_c
}:
stdenv.mkDerivation rec {
pname = "libubox";
version = "unstable-2024-04-09";
src = fetchFromGitea {
domain = "git.dgnum.eu";
owner = "DGNum";
repo = "libubox";
rev = "1c4b2dc4c12848e1b70b11e1cb2139ca8f19c860";
hash = "sha256-aPhGJ7viXQmnoQRY8DuRvtwtxSy+S4qPj1fBsK066Yc=";
};
nativeBuildInputs = [
cmake
lua
];
buildInputs = [
lua
json_c
];
# Otherwise, CMake cannot find jsoncpp?
env.NIX_CFLAGS_COMPILE = toString [ "-I${json_c.dev}/include/json-c" "-D JSONC" "-D LUA_COMPAT_MODULE" ];
cmakeFlags = [
"-DBUILD_EXAMPLES=off"
# TODO: it explode at install phase.
"-DBUILD_LUA=on"
"-DLUAPATH=${placeholder "out"}/lib/lua/${lua.luaversion}/"
];
meta = {
description = "";
homepage = "https://git.openwrt.org/project/libubox.git";
maintainers = with lib.maintainers; [ raitobezarius ];
mainProgram = "libubox";
platforms = lib.platforms.all;
};
}

View file

@ -1,17 +0,0 @@
{
stdenv
, busybox
, buildPackages
, callPackage
, pseudofile
, runCommand
, writeText
} : { eraseBlockSize, bootableRootDirectory }:
let
endian = if stdenv.isBigEndian then "--big-endian" else "--little-endian";
in runCommand "frob-jffs2" {
depsBuildBuild = [ buildPackages.mtdutils ];
} ''
tree=${bootableRootDirectory}
(cd $tree && mkfs.jffs2 --compression-mode=size ${endian} -e ${toString eraseBlockSize} --enable-compressor=lzo --pad --root . --output $out --squash --faketime)
''

View file

@ -9,7 +9,6 @@
ip link set up dev ${ifname} ip link set up dev ${ifname}
(in_outputs ${name} (in_outputs ${name}
echo ${ifname} > ifname echo ${ifname} > ifname
cat /sys/class/net/${ifname}/address > ether
) )
''; '';
} }

View file

@ -39,7 +39,6 @@ let
, contents ? [] , contents ? []
, buildInputs ? [] , buildInputs ? []
, isTrigger ? false , isTrigger ? false
, passthru ? {}
} @ args: } @ args:
stdenvNoCC.mkDerivation { stdenvNoCC.mkDerivation {
# we use stdenvNoCC to avoid generating derivations with names # we use stdenvNoCC to avoid generating derivations with names
@ -51,8 +50,6 @@ let
dependencies = builtins.map (d: d.name) dependencies; dependencies = builtins.map (d: d.name) dependencies;
contents = builtins.map (d: d.name) contents; contents = builtins.map (d: d.name) contents;
builder = ./builder.sh; builder = ./builder.sh;
inherit passthru;
}; };
longrun = { longrun = {
@ -103,18 +100,7 @@ let
serviceType = "bundle"; serviceType = "bundle";
inherit contents dependencies; inherit contents dependencies;
}); });
structuredBundle = {
name
, contents ? {}
, dependencies ? []
, ...
} @ args: service (args // {
serviceType = "bundle";
contents = builtins.attrValues contents;
inherit dependencies;
passthru.components = contents;
});
target = bundle; target = bundle;
in { in {
inherit target bundle oneshot longrun output structuredBundle; inherit target bundle oneshot longrun output;
} }

View file

@ -1,5 +1,4 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -Eeuo pipefail
ssh_command=${SSH_COMMAND-ssh} ssh_command=${SSH_COMMAND-ssh}
@ -14,24 +13,19 @@ case "$1" in
reboot="soft" reboot="soft"
shift shift
;; ;;
"--root")
root_prefix="$2"
shift
shift
;;
esac esac
target_host=$1 target_host=$1
shift shift
if [ -z "$target_host" ] ; then if [ -z "$target_host" ] ; then
echo Usage: liminix-rebuild \[--no-reboot\] \[--fast\] target-host params echo Usage: liminix-rebuild \[--no-reboot\] target-host params
exit 1 exit 1
fi fi
if toplevel=$(nix-build "$@" -A outputs.systemConfiguration --no-out-link); then if toplevel=$(nix-build "$@" -A outputs.systemConfiguration --no-out-link); then
echo systemConfiguration $toplevel echo systemConfiguration $toplevel
min-copy-closure --root "$root_prefix" $target_host $toplevel min-copy-closure $target_host $toplevel
$ssh_command $target_host $toplevel/bin/install $ssh_command $target_host $toplevel/bin/install
case "$reboot" in case "$reboot" in
reboot) reboot)

View file

@ -1,6 +1,5 @@
struct root_opts { struct root_opts {
char *device; char *device;
char *altdevice; /* For A/B schemas */
char *fstype; char *fstype;
char *mount_opts; char *mount_opts;
}; };

View file

@ -65,18 +65,12 @@ static char * eat_param(char *p, char *param_name, char **out)
return p; return p;
} }
#define SCAN_CMDLINE(cmdline, identifier, field) do { \
for (char* p = strdup(cmdline); *p; p++) { \
p = eat_param(p, identifier, &(opts->field)); \
} \
} while(0)
void parseopts(char * cmdline, struct root_opts *opts) { void parseopts(char * cmdline, struct root_opts *opts) {
SCAN_CMDLINE(cmdline, "root=", device); for(char *p = cmdline; *p; p++) {
SCAN_CMDLINE(cmdline, "rootfstype=", fstype); p = eat_param(p, "root=", &(opts->device));
SCAN_CMDLINE(cmdline, "rootflags=", mount_opts); p = eat_param(p, "rootfstype=", &(opts->fstype));
SCAN_CMDLINE(cmdline, "rootalt=", altdevice); p = eat_param(p, "rootflags=", &(opts->mount_opts));
};
} }
#ifdef TESTS #ifdef TESTS
@ -90,8 +84,6 @@ void parseopts(char * cmdline, struct root_opts *opts) {
#define S(x) #x #define S(x) #x
#define expect_equal(actual, expected) \ #define expect_equal(actual, expected) \
if(!actual || strcmp(actual, expected)) die("%d: expected \"%s\", got \"%s\"", __LINE__, expected, actual); if(!actual || strcmp(actual, expected)) die("%d: expected \"%s\", got \"%s\"", __LINE__, expected, actual);
#define expect_null(actual) \
if (actual) die("%d: expected null, got \"%s\"", __LINE__, actual);
int main() int main()
@ -99,7 +91,6 @@ int main()
struct root_opts opts = { struct root_opts opts = {
.device = "/dev/hda1", .device = "/dev/hda1",
.fstype = "xiafs", .fstype = "xiafs",
.altdevice = NULL,
.mount_opts = NULL .mount_opts = NULL
}; };
char *buf; char *buf;
@ -111,22 +102,6 @@ int main()
expect_equal(opts.fstype, "ubifs"); expect_equal(opts.fstype, "ubifs");
expect_equal(opts.mount_opts, "subvol=1"); expect_equal(opts.mount_opts, "subvol=1");
// finds rootalt= options
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs rootflags=subvol=1 fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0 rootalt=/dev/mtdblock6 foo");
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
expect_equal(opts.device, "/dev/mtdblock0");
expect_equal(opts.altdevice, "/dev/mtdblock6");
expect_equal(opts.fstype, "ubifs");
expect_equal(opts.mount_opts, "subvol=1");
// Ensure that `altdevice` is NULL.
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 fw_devlink=off rootfstype=ubifs mtdparts=phram0:19791872(rootfs) phram.phram=phram0,33554432,19791872,65536 rootfstype=jffs2 root=/dev/mtdblock0");
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
expect_equal(opts.device, "/dev/mtdblock0");
expect_null(opts.altdevice);
expect_equal(opts.fstype, "jffs2");
expect_null(opts.mount_opts);
// in case of duplicates, chooses the latter // in case of duplicates, chooses the latter
// also: works if the option is end of string // also: works if the option is end of string
buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0"); buf = strdup("liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/ubi0_4 rootfstype=ubifs fw_devlink=off mtdparts=phram0:18M(rootfs) phram.phram=phram0,0x40400000,18874368,65536 root=/dev/mtdblock0");
@ -159,15 +134,13 @@ int main()
if(opts.fstype) die("expected null rootfstype, got \"%s\"", opts.fstype); if(opts.fstype) die("expected null rootfstype, got \"%s\"", opts.fstype);
if(opts.device) die("expected null root, got \"%s\"", opts.device); if(opts.device) die("expected null root, got \"%s\"", opts.device);
if(opts.mount_opts) die("expected null mount_opts, got \"%s\"", opts.mount_opts); if(opts.mount_opts) die("expected null mount_opts, got \"%s\"", opts.mount_opts);
if(opts.altdevice) die("expected null altdevice, got \"%s\"", opts.altdevice);
// provides empty strings for empty options // provides empty strings for empty options
buf = strdup("liminix rootfstype= fw_devlink=off root= rootalt= /dev/hda1"); buf = strdup("liminix rootfstype= fw_devlink=off root= /dev/hda1");
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts); memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
if(strlen(opts.fstype)) die("expected empty rootfstype, got \"%s\"", opts.fstype); if(strlen(opts.fstype)) die("expected empty rootfstype, got \"%s\"", opts.fstype);
if(strlen(opts.device)) die("expected empty root, got \"%s\"", opts.device); if(strlen(opts.device)) die("expected null root, got \"%s\"", opts.device);
if(strlen(opts.altdevice)) die("expected empty rootalt, got \"%s\"", opts.altdevice);
expect_equal("01", pr_u32(1)); expect_equal("01", pr_u32(1));
expect_equal("ab", pr_u32(0xab)); expect_equal("ab", pr_u32(0xab));

View file

@ -4,20 +4,16 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/stat.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <dirent.h>
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */ #include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#include "opts.h" #include "opts.h"
#define ERR(x) write(2, x, strlen(x)) #define ERR(x) write(2, x, strlen(x))
#define AVER(c) do { if(c < 0) { ERR("failed: " #c ": error=0x" ); pr_u32(errno); ERR ( " - "); ERR(strerror(errno)); ERR("\n"); } } while(0) #define AVER(c) do { if(c < 0) { ERR("failed: " #c ": error=0x" ); pr_u32(errno); ERR("\n"); } } while(0)
char * pr_u32(int32_t input); char * pr_u32(int32_t input);
@ -48,25 +44,6 @@ static int fork_exec(char * command, char *args[])
return execve(command, args, NULL); return execve(command, args, NULL);
} }
static void debug_listdir(const char * path)
{
DIR *mydir;
struct dirent *myfile;
struct stat mystat;
char buf[512];
mydir = opendir(path);
while((myfile = readdir(mydir)) != NULL)
{
sprintf(buf, "%s/%s", path, myfile->d_name);
stat(buf, &mystat);
printf("%llu", mystat.st_size);
printf(" %s\n", myfile->d_name);
}
closedir(mydir);
}
char banner[] = "Running pre-init...\n"; char banner[] = "Running pre-init...\n";
char buf[COMMAND_LINE_SIZE]; char buf[COMMAND_LINE_SIZE];
@ -111,32 +88,13 @@ int main(int argc, char *argv[], char *envp[])
write(1, ", opts=", 7); write(1, ", opts=", 7);
write(1, opts.mount_opts, strlen(opts.mount_opts)); write(1, opts.mount_opts, strlen(opts.mount_opts));
} }
if(opts.altdevice) {
write(1, ", altdevice=", 12);
write(1, opts.altdevice, strlen(opts.altdevice));
}
write(1, ")\n", 2); write(1, ")\n", 2);
AVER(mount(opts.device, "/target/persist", opts.fstype, 0, opts.mount_opts));
if(!opts.altdevice) {
AVER(mount(opts.device, "/target/persist", opts.fstype, 0, opts.mount_opts));
} else {
if(mount(opts.device, "/target/persist", opts.fstype, 0, opts.mount_opts) < 0) {
ERR("failed to mount primary device, mount the alternative device\n");
AVER(mount(opts.altdevice, "/target/persist", opts.fstype, 0, opts.mount_opts));
}
}
// FUTUREWORK: any failure using `opts.device` should force us to consider rerunning this with the alternative rootfs.
AVER(mount("/target/persist/nix", "/target/nix", AVER(mount("/target/persist/nix", "/target/nix",
"bind", MS_BIND, NULL)); "bind", MS_BIND, NULL));
char *exec_args[] = { "activate", "/target", NULL }; char *exec_args[] = { "activate", "/target", NULL };
if (fork_exec("/target/persist/activate", exec_args) < 0) { AVER(fork_exec("/target/persist/activate", exec_args));
ERR("failed to activate the system\n");
pr_u32(errno); ERR ( " - "); ERR(strerror(errno)); ERR("\n");
goto failsafe;
}
AVER(chdir("/target")); AVER(chdir("/target"));
AVER(mount("/target", "/", "bind", MS_BIND | MS_REC, NULL)); AVER(mount("/target", "/", "bind", MS_BIND | MS_REC, NULL));
@ -144,26 +102,7 @@ int main(int argc, char *argv[], char *envp[])
argv[0] = "init"; argv[0] = "init";
argv[1] = NULL; argv[1] = NULL;
AVER(execve("/persist/init", argv, envp)); AVER(execve("/persist/init", argv, envp));
} }
failsafe:
debug_listdir("/");
debug_listdir("/target");
ERR("failed to mount the rootfs\n");
ERR("final stand using the failsafe initialization method\n");
ERR("the boot process is manual from now on\n");
argv[0] = "init";
argv[1] = NULL;
// Attempt to unmount the /target mount-bind.
AVER(umount("/target"));
AVER(execve("/failsafe-init", argv, envp));
debug_listdir("/");
debug_listdir("/target");
die(); die();
} }

View file

@ -2,15 +2,14 @@
qemuLim qemuLim
, socat , socat
, writeShellScript , writeShellScript
, writeFennel
, runCommand , runCommand
, fennel
, lib , lib
, lua , lua
, pkgsBuildBuild , pkgsBuildBuild
}: let }: let
writeFennel = pkgsBuildBuild.writeFennel.override { inherit lua; }; run-liminix-vm = pkgsBuildBuild.writeFennel "run-liminix-vm" {
run-liminix-vm = writeFennel "run-liminix-vm" { packages = [ qemuLim lua.pkgs.luaposix lua.pkgs.fennel ];
packages = [ qemuLim lua.pkgs.luaposix fennel ];
} ./run-liminix-vm.fnl; } ./run-liminix-vm.fnl;
connect = writeShellScript "connect-vm" '' connect = writeShellScript "connect-vm" ''
export PATH="${lib.makeBinPath [socat]}:$PATH" export PATH="${lib.makeBinPath [socat]}:$PATH"

View file

@ -1,35 +0,0 @@
{ stdenv, fetchFromGitea, lib, cmake, libubox, json_c, lua, defaultSocketLocation ? "/run/ubus/ubus.sock" }:
stdenv.mkDerivation {
pname = "ubus";
version = "unstable-04-09-2024";
src = fetchFromGitea {
domain = "git.dgnum.eu";
owner = "DGNum";
repo = "ubus";
rev = "ebb1dc92e4985538a8e18b7e926264118138f281";
hash = "sha256-fo4zleC9R6uzlcOJ/jQ0t0nSBHUAq/uqPVd9xJdkAM0=";
};
# We don't use /var/run/ in Liminix by default.
postPatch = ''
substituteInPlace CMakeLists.txt \
--replace-fail "/var/run/ubus/ubus.sock" "${defaultSocketLocation}"
'';
nativeBuildInputs = [
cmake
];
buildInputs = [
lua
libubox
json_c
];
cmakeFlags = [
"-DBUILD_LUA=on"
"-DLUAPATH=${placeholder "out"}/lib/lua/${lua.luaversion}"
"-DBUILD_EXAMPLES=off"
];
}

View file

@ -1,39 +0,0 @@
# usb modeswitch without udev, tcl, coreutils, bash dependencies
{ stdenv
, lib
, fetchurl
, pkg-config
, libusb1
}:
let
pname = "usb-modeswitch";
version = "2.6.0";
in stdenv.mkDerivation {
inherit pname version;
src = fetchurl {
url = "http://www.draisberghof.de/usb_modeswitch/${pname}-${version}.tar.bz2";
sha256 = "18wbbxc5cfsmikba0msdvd5qlaga27b32nhrzicyd9mdddp265f2";
};
preBuild = ''
makeFlagsArray+=(LIBS="$($PKG_CONFIG --libs --cflags libusb-1.0)")
'';
makeFlags = [
"PREFIX=$(out)"
"usb_modeswitch"
];
buildInputs = [ libusb1 ];
nativeBuildInputs = [ pkg-config ];
installPhase = ''
mkdir -p $out/bin
cp usb_modeswitch $out/bin
'';
meta = {
license = lib.licenses.gpl2;
maintainers = [];
};
}

View file

@ -27,7 +27,7 @@ name :
echo "#!${lua}/bin/lua ${luaFlags}" echo "#!${lua}/bin/lua ${luaFlags}"
echo "package.path = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luapath)} .. package.path" echo "package.path = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luapath)} .. package.path"
echo "package.cpath = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luacpath)} .. package.cpath" echo "package.cpath = ${lib.strings.escapeShellArg (builtins.concatStringsSep "" luacpath)} .. package.cpath"
echo "local ok, stdlib = pcall(require,'posix.stdlib'); if ok then stdlib.setenv('PATH', \"${lib.makeBinPath packages}\" .. \":\" .. os.getenv('PATH')) end" echo "local ok, stdlib = pcall(require,'posix.stdlib'); if ok then stdlib.setenv('PATH',${lib.escapeShellArg (lib.makeBinPath packages)} .. \":\" .. os.getenv('PATH')) end"
fennel ${if correlate then "--correlate" else ""} --compile ${source} fennel ${if correlate then "--correlate" else ""} --compile ${source}
) > ${name}.lua ) > ${name}.lua
''; '';

View file

@ -10,5 +10,4 @@
tftpboot = import ./tftpboot/test.nix; tftpboot = import ./tftpboot/test.nix;
updown = import ./updown/test.nix; updown = import ./updown/test.nix;
inout = import ./inout/test.nix; inout = import ./inout/test.nix;
custom-shell = import ./custom-shell/test.nix;
} }

View file

@ -1,7 +0,0 @@
set timeout 60
spawn socat unix-connect:vm/console -
expect {
"root@liminix blah blah > " { exit 0 }
timeout { exit 1 }
}

View file

@ -1,13 +0,0 @@
{ config, pkgs, lib, ... } :
let
inherit (pkgs.liminix.networking) interface address hostapd route dnsmasq;
inherit (pkgs.liminix.services) oneshot longrun bundle target;
in rec {
imports = [
../../modules/network
];
defaultProfile.prompt = "$(whoami)@$(hostname) blah blah > ";
defaultProfile.packages = with pkgs; [ ];
}

View file

@ -1,21 +0,0 @@
{
liminix
, nixpkgs
}:
let img = (import liminix {
inherit nixpkgs;
device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix;
}).outputs.default;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [
expect socat
] ;
} ''
. ${../test-helpers.sh}
mkdir vm
${img}/run.sh --background ./vm
expect ${./check-prompt.expect} |tee output && mv output $out
''

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu/"; device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix; liminix-config = ./configuration.nix;
}).outputs.vmroot; }).outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; }; pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" { in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
expect expect

View file

@ -4,7 +4,7 @@
}: }:
let let
overlay = import "${liminix}/overlay.nix"; overlay = import "${liminix}/overlay.nix";
pkgs = import nixpkgs { overlays = [overlay]; }; pkgs = import <nixpkgs> { overlays = [overlay]; };
script = pkgs.writeFennelScript "foo" [] ./hello.fnl; script = pkgs.writeFennelScript "foo" [] ./hello.fnl;
inherit (pkgs.lua.pkgs) fifo; inherit (pkgs.lua.pkgs) fifo;
netlink = pkgs.netlink-lua; netlink = pkgs.netlink-lua;

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu/"; device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix; liminix-config = ./configuration.nix;
}).outputs.vmroot; }).outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; }; pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" { in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
expect expect

View file

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

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu/"; device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix; liminix-config = ./configuration.nix;
}).outputs.vmroot; }).outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; }; pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" { in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
expect expect

View file

@ -13,6 +13,7 @@ let
in { in {
imports = [ imports = [
../../vanilla-configuration.nix ../../vanilla-configuration.nix
../../modules/outputs/jffs2.nix
]; ];
config = { config = {
services.sshd = longrun { services.sshd = longrun {

View file

@ -8,7 +8,7 @@ let lmx = (import liminix {
}); });
rogue = lmx.pkgs.rogue; rogue = lmx.pkgs.rogue;
img = lmx.outputs.vmroot; img = lmx.outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; }; pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" { in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
expect expect

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu"; device = import "${liminix}/devices/qemu";
liminix-config = ./configuration.nix; liminix-config = ./configuration.nix;
}).outputs.default; }).outputs.default;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; }; pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
inherit (pkgs.pkgsBuildBuild) routeros; inherit (pkgs.pkgsBuildBuild) routeros;
in pkgs.runCommand "check" { in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [

View file

@ -1,6 +1,5 @@
{ {
liminix, liminix
...
}: }:
let check = deviceName : config : let check = deviceName : config :
let derivation = (import liminix { let derivation = (import liminix {

View file

@ -6,7 +6,7 @@ let img = (import liminix {
device = import "${liminix}/devices/qemu/"; device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix; liminix-config = ./configuration.nix;
}).outputs.vmroot; }).outputs.vmroot;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; }; pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" { in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
expect expect

View file

@ -7,7 +7,6 @@ in rec {
../../modules/wlan.nix ../../modules/wlan.nix
../../modules/hostapd ../../modules/hostapd
../../modules/network ../../modules/network
./wpa_supplicant.nix
]; ];
services.hostap = config.system.service.hostapd.build { services.hostap = config.system.service.hostapd.build {
@ -28,21 +27,5 @@ in rec {
}; };
}; };
services.wpa_supplicant = config.system.service.wpa_supplicant.build { defaultProfile.packages = with pkgs; [ tcpdump ] ;
interface = "wlan1";
driver = "nl80211";
config-file = pkgs.writeText "wpa_supplicant.conf" ''
country=us
update_config=1
ctrl_interface=/run/wpa_supplicant
network={
scan_ssid=1
ssid="liminix"
psk="colourless green ideas"
}
'';
};
defaultProfile.packages = with pkgs; [ tcpdump wpa_supplicant ];
} }

View file

@ -3,11 +3,10 @@
, nixpkgs , nixpkgs
}: }:
let img = (import liminix { let img = (import liminix {
inherit nixpkgs; device = import "${liminix}/devices/qemu-armv7l/";
device = import "${liminix}/devices/qemu/";
liminix-config = ./configuration.nix; liminix-config = ./configuration.nix;
}).outputs.default; }).outputs.default;
pkgs = import nixpkgs { overlays = [(import ../../overlay.nix)]; }; pkgs = import <nixpkgs> { overlays = [(import ../../overlay.nix)]; };
in pkgs.runCommand "check" { in pkgs.runCommand "check" {
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
expect socat expect socat

View file

@ -14,10 +14,10 @@ expect {
} }
expect "#" expect "#"
while { $FINISHED < 10 } { while { $FINISHED < 10 } {
send "date && grep CTRL-EVENT-CONNECTED /run/uncaught-logs/* || echo \$NOT\r\n" send "date && grep AP-ENABLED /run/uncaught-logs/* || echo \$NOT\r\n"
expect { expect {
"wlan1: CTRL-EVENT-CONNECTED" { set FINISHED 999; set EXIT 0; } "wlan0: AP-ENABLED" { set FINISHED 999; set EXIT 0; }
"not_present" { send_user "waiting ...\n" ; sleep 5 } "not_present" { send_user "waiting ...\n" ; sleep 5 }
} }
set FINISHED [ expr $FINISHED + 1 ] set FINISHED [ expr $FINISHED + 1 ]

View file

@ -1,21 +0,0 @@
{
liminix,
wpa_supplicant,
lib,
}:
{
interface,
driver,
config-file,
}:
let
inherit (liminix.services) longrun;
inherit (lib.strings) escapeShellArg;
in
longrun {
name = "wpa_supplicant";
run =
''
${wpa_supplicant}/bin/wpa_supplicant -D${driver} -i${interface} -c ${config-file}
'';
}

View file

@ -1,15 +0,0 @@
{ config, lib, pkgs, ... }:
with lib; {
options.system.service.wpa_supplicant = mkOption { type = pkgs.liminix.lib.types.serviceDefn; };
config.system.service.wpa_supplicant = config.system.callService ./wpa_service.nix {
interface = mkOption {
type = types.str;
};
driver = mkOption {
type = types.str;
};
config-file = mkOption {
type = types.package;
};
};
}