1
0
forked from dan/liminix

Compare commits

...

24 Commits

Author SHA1 Message Date
Arnout Engelen
04895f9cf6
openwrt: update to v23.05.2 2024-01-25 12:29:03 +01:00
dan
5f2d1660bd Merge pull request 'belkin-rt3200: Enable watchdog drivers' (#3) from sinavir/liminix:add_belkin_watchdog into main
Reviewed-on: dan/liminix#3
2024-01-24 14:36:08 +00:00
sinavir
7642e23c0a belkin-rt3200: Enable watchdog drivers 2024-01-24 13:38:55 +01:00
83ee488e4c systemconfig: /boot needs to go inside /persist 2024-01-09 13:10:02 +00:00
f19a937eda omnia needs MARVELL_PHY for the WAN port to work
interestingly, we only see this when it boots from mmc, because
for tftpboot the bootloader has already performed negotiation
and therefore it works despite the missing option.
2024-01-09 13:07:14 +00:00
f0490f37d5 turris omnia: tidy config, remove dead bits 2024-01-08 19:22:42 +00:00
c1101d3af5 make extlinux work with liminix-rebuild
add /boot to the systemConfiguration closure
2024-01-08 18:58:07 +00:00
9a3d7a387e correct turris omnia root device 2024-01-08 18:55:41 +00:00
228c0a1668 pass rootOptions config as rootflags= kernel cmdline opt 2024-01-08 18:54:49 +00:00
63f034e362 preinit: parse rootflags= in kernel command line 2024-01-08 00:35:13 +00:00
6971d03520 preinit: check return from write() 2024-01-07 21:24:16 +00:00
7bc9cb6c55 why is extlink hardcoding root device? 2024-01-07 20:30:23 +00:00
a251ceeb99 omnia releng 2024-01-07 16:54:44 +00:00
38a7f0b03b turris omnia: add all lan devices
I think we might turn "lan" into a bridge, but that's for later
2024-01-07 16:54:44 +00:00
c0c4752350 systemconfig "install" cmd honours prefix on source 2024-01-07 16:54:44 +00:00
3c941b4ce2 partial btrfs support
doesn't actually know how to make the filesystem, just
kernel config and accept it as a valid option
2024-01-07 16:43:43 +00:00
243295aab8 recovery config for turris omnia 2024-01-07 14:58:46 +00:00
45e8db09e1 liminix-rebuild: escape brackets in usage message 2024-01-07 14:18:19 +00:00
2a93f24a58 add turris "schnapps" tool
in its current state this is useful for turris omnia only, but will
allow us to do installs and rollback to turris os if needed.
2024-01-05 00:07:01 +00:00
64898eada8 mount tmpfs on /tmp
too much stuff doesn't work without it and it's not
all worth patching
2024-01-04 23:22:02 +00:00
136c5e6f32 alphabetize package list 2024-01-04 10:15:23 +00:00
fa9a2c6413 add btrfs-progs 2024-01-04 09:33:44 +00:00
049cdbb610 turris omnia: don't hardcode rootfsType 2024-01-03 20:18:07 +00:00
5ee4adff10 NEWS: we now expect Liminix 23.11 2024-01-03 19:44:49 +00:00
24 changed files with 497 additions and 132 deletions

8
NEWS
View File

@ -23,5 +23,13 @@ the name of an outputs that gloms together other filesystem-like
outputs with some kind of partition table - so we might in future have
gptimage or lvmimage or ubimage.
2024-01-03
Liminix is now targeted to Nixpkgs 23.11 (not 23.05 as previously).
Upstream changes that have led to incompatible Liminix changes are:
* newer U-Boot version
* util-linux can now be built (previously depended on systemd)

View File

@ -3707,9 +3707,10 @@ Here is scope of work for Turris:
recovery/install.
- disk partitioning tools and mkfs stuff
- kernel with all the filesystems
- dhcp client for connecting to wired network
(II) we need insttuctions for building the real system
(II) we need instructions for building the real system
and using min-copy-closure to copy and install the system
configuration of the real one into /mnt
@ -3742,14 +3743,105 @@ To be any use, the test needs to be end-to-end - as in, rather than
just checking some files are copied, test that the machine rebooted
successfully
Fri Dec 29 18:36:16 GMT 2023
Our test for liminix-rebuild uses qemu block device and ext4 instead
of phram because -device loader doesn't seem to survive a reboot.
And it needs some free space in the ext4 partition inside the
mbr image so that it can install new stuff. However, the
filesystem is sized to be near-full.
If the mbrimage output is to be much use, probably there should be
some way of telling it how big the disk is. Maybe it should use
hardware.flash.size?
UBI also does a bad job of integrating into the hardware.flash hierarchy
(but ubi is also more complicated as the ubi volumes are "nested" inside
an MTD partition)
To move forwards with this test I think I will make it not depend on
mbrimage for now, but we have to come back to this. Maybe importing
the mbrimage module provides new hardware.disk = { partitions, size etc}
config options.
Sun Dec 31 23:52:04 GMT 2023
https://developer.ridgerun.com/wiki/index.php/Setting_up_fw_printenv_to_modify_u-boot_environment_variables#Preparing_the_fw_env.config_file
can we extract the fw_env config data somehow to produce an appropriate
file for the device?
the device config needs to specify partition name and offset at minimum,
possibly also size.
we can create a service that writes the config based on those values. but
if we are to be using fw_setenv from the shell, there is no service
which depends on that service. whatever defines the service also needs
to add it to system.services so that the recovery system can specify it
Sat Jan 6 12:30:27 GMT 2024
How do we min-copy-closure to the device when we don't have anything
hooked to the LAN port? It's rather easy to break the WAN connection
when it involves going out to the internet and back
* Don't want to plug it into the actual lan because it's doing dhcp service
and that is going to confuse
* the machine we're copying from is loaclhost
* we could do some kind of port forwarding thing? maybe a port forward on
run-border-vm qemu user networking ...
* static route on loaclhost?
512 sudo ip netns add test-lan
514 sudo ip link set dev enp1s0 netns test-lan
525 sudo ip link add veth-test-lan type veth peer veth1 netns test-lan
533 sudo ip netns exec test-lan ip link add name br0 type bridge
536 sudo ip netns exec test-lan ip link set veth1 master br0
537 sudo ip netns exec test-lan ip link set enp1s0 master br0
sudo ip netns exec test-lan /nix/store/dh66q9k402pwpmmgc983xwmwb3vvvjbr-busybox-1.36.1/bin/busybox udhcpc -i br0
then we could add a route to 10.8.0.1/32 with dev veth-test-lan ?
Sat Jan 6 20:52:45 GMT 2024
This is all beside the point right now because the _recovery_ system
does not run all this stuff - it just has a dhcp client on the lan
interface. We could plug it straight into the switch.
COPYING /nix/store/dlz86nip271ybaz0cip7bgkbzijk0cr7-make-stuff-mips-unknown-linux-musl TO //persist
As we already just plugged it into enp1s0 on loaclhost, could we
do somethin to put it on the lan from there? add it to vbridge0?
Sun Jan 7 15:30:57 GMT 2024
/nix/store/gr255qjxijksf9361glsj5lz0cklassx-profile
Turns out we should have used a working ethernet cable.
md5sum /persist/activate
8eb0760c39cdee0b141b15bbafbc94a0 /persist/activate BAD
6c27b75cbe9f2ce87c1fd1425362108f /persist/activate GOOD
8eb0760c39cdee0b141b15bbafbc94a0 /persist/activate
Sun Jan 7 15:31:14 GMT 2024
OK, so
# on device
mount /dev/mmcblk0p1 /mnt
[ take a snapshot if needed ]
[ clear out the turrisos files ]
ls /mnt/@
# on build
$ nix-build -I liminix-config=./examples/rotuer.nix --arg device "import ./devices/turris-omnia" -A outputs.systemConfiguration
$ nix-shell --run "min-copy-closure -r /mnt/@ root@recovery.lan result "
# on device
$ mkdir /mnt/@/persist
$ /mnt/@/nix/store/swf3vn9bzx198c0cwp6naq0glqa9192n-make-stuff-armv7l-unknown-linux-musleabihf/bin/install /mnt/@/
this fails because it tries to copy from the unprefixed nix
store. Also probably it should mkdir $prefix/persist. Also it needs to
create $prefix/boot: it's too late to do that with `activate`
because u-boot will need it to exist in order to load the initramfs
that runs activate

View File

@ -57,8 +57,8 @@
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${pkgs.openwrt.applyPatches.mediatek}
@ -144,6 +144,10 @@
# SERIAL_8250_NR_UARTS="3";
# SERIAL_8250_RUNTIME_UARTS="3";
SERIAL_OF_PLATFORM="y";
# Must enble hardware watchdog drivers. Else the device reboots after several seconds
WATCHDOG = "y";
MEDIATEK_WATCHDOG = "y";
};
};
boot = {

View File

@ -7,8 +7,8 @@
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
config = {
MTD = "y";

View File

@ -152,8 +152,8 @@
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
# Mainline linux 5.19 doesn't have device-tree support for

View File

@ -131,8 +131,8 @@
kernel = {
src = pkgs.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${openwrt.applyPatches.ramips}

View File

@ -127,8 +127,8 @@
kernel = {
src = pkgs.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${openwrt.applyPatches.ramips}

View File

@ -2,6 +2,27 @@
description = ''
Turris Omnia
************
This is a 32 bit ARMv7 MVEBU device, which is usually shipped with
TurrisOS, an OpenWrt-based system. Rather than reformatting the
builtin storage, we install Liminix on to the existing btrfs
filesystem so that the vendor snapshot/recovery system continues
to work (and provides you an easy rollback if you decide you don't
like Liminix after all).
The install process is designed so that you should not need to open
the device and add a serial console (although it may be handy
for visibility and in case anything goes wrong). In outline
1. build a "recovery" system with useful btrfs tools
2. boot that system using TFTP or a USB stick
3. once booted, mount the real root filesystem on /mnt
4. take a snapshot using schnapps, and then delete everything
5. use min-copy-closure -d /mnt/@ to copy the real configuration
to the device
6. reboot into a fully operational system
Detailed instructions to follow...
'';
system = {
@ -30,7 +51,6 @@
imports = [
../../modules/arch/arm.nix
../../modules/outputs/tftpboot.nix
../../modules/outputs/ext4fs.nix
../../modules/outputs/mbrimage.nix
../../modules/outputs/extlinux.nix
];
@ -40,8 +60,8 @@
kernel = {
src = pkgs.pkgsBuildBuild.fetchurl {
name = "linux.tar.gz";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.71.tar.gz";
hash = "sha256-yhO2cXIeIgUxkSZf/4aAsF11uxyh+UUZu6D1h92vCD8=";
url = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.137.tar.gz";
hash = "sha256-PkdzUKZ0IpBiWe/RS70J76JKnBFzRblWcKlaIFNxnHQ=";
};
extraPatchPhase = ''
${pkgs.openwrt.applyPatches.mvebu}
@ -110,6 +130,7 @@
MVNETA_BM_ENABLE = "y";
SRAM = "y"; # mmio-sram is "compatible" for bm_bppi reqd by BM
PHY_MVEBU_A38X_COMPHY = "y"; # for eth2
MARVELL_PHY = "y";
MVPP2 = "y";
MV_XOR = "y";
@ -127,13 +148,12 @@
NET_DSA_MV88E6XXX = "y"; # depends on PTP_1588_CLOCK_OPTIONAL
};
};
rootfsType = "ext4";
boot = {
commandLine = [
"console=ttyS0,115200"
"pcie_aspm=off" # ath9k pci incompatible with PCIe ASPM
];
imageFormat = "fit";
};
filesystem =
let
@ -142,9 +162,9 @@
name = "wlan-firmware";
phases = ["installPhase"];
installPhase = ''
mkdir $out
cp -r ${pkgs.linux-firmware}/lib/firmware/ath10k/QCA988X $out
'';
mkdir $out
cp -r ${pkgs.linux-firmware}/lib/firmware/ath10k/QCA988X $out
'';
};
in dir {
lib = dir {
@ -176,7 +196,7 @@
defaultOutput = "mtdimage";
loadAddress = lim.parseInt "0x00800000"; # "0x00008000";
entryPoint = lim.parseInt "0x00800000"; # "0x00008000";
rootDevice = "/dev/mtdblock0";
rootDevice = "/dev/mmcblk0p1";
dts = {
src = "${config.system.outputs.kernel.modulesupport}/arch/arm/boot/dts/armada-385-turris-omnia.dts";
@ -210,7 +230,7 @@
# per
# https://www.kernel.org/doc/html/latest/networking/dsa/configuration.html#affinity-of-user-ports-to-cpu-ports
# but apparently OpenWrt doesn't either so maybe it's more
# complicated than it looks
# complicated than it looks.
wan = link.build {
# in armada-38x.dtsi this is eth2. It may be connected to
@ -219,9 +239,13 @@
ifname = "wan";
};
lan = link.build {
ifname = "lan1";
};
lan0 = link.build { ifname = "lan0"; };
lan1 = link.build { ifname = "lan1"; };
lan2 = link.build { ifname = "lan2"; };
lan3 = link.build { ifname = "lan3"; };
lan4 = link.build { ifname = "lan4"; };
lan5 = link.build { ifname = "lan5"; };
lan = lan0; # maybe we should build a bridge?
wlan = link.build {
ifname = "wlan0";

82
examples/recovery.nix Normal file
View File

@ -0,0 +1,82 @@
{ config, pkgs, lib, ... } :
let
inherit (pkgs) serviceFns;
svc = config.system.service;
inherit (pkgs.pseudofile) dir symlink;
inherit (pkgs.liminix.services) oneshot longrun bundle target;
in rec {
imports = [
../modules/network
../modules/ssh
../modules/schnapps
../modules/outputs/mtdimage.nix
../modules/outputs/mbrimage.nix
../modules/outputs/tftpboot.nix
../modules/outputs/ubifs.nix
../modules/outputs/ubimage.nix
../modules/outputs/jffs2.nix
../modules/outputs/ext4fs.nix
];
kernel.config = {
BTRFS_FS = "y";
};
boot.tftp = {
ipaddr = "10.0.0.8"; # my address
serverip = "10.0.0.1"; # build machine or other tftp server
};
hostname = "recovery";
services.dhcpc = svc.network.dhcp.client.build {
interface = config.hardware.networkInterfaces.lan2;
# don't start DHCP until the hostname is configured,
# so it can identify itself to the DHCP server
dependencies = [ config.services.hostname ];
};
services.sshd = svc.ssh.build { };
services.defaultroute4 = svc.network.route.build {
via = "$(output ${services.dhcpc} router)";
target = "default";
dependencies = [services.dhcpc];
};
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";
};
mnt = dir {};
};
rootfsType = "squashfs";
users.root = {
# the password is "secret". Use mkpasswd -m sha512crypt to
# create this hashed password string
passwd = "$6$y7WZ5hM6l5nriLmo$5AJlmzQZ6WA.7uBC7S8L4o19ESR28Dg25v64/vDvvCN01Ms9QoHeGByj8lGlJ4/b.dbwR9Hq2KXurSnLigt1W1";
};
defaultProfile.packages = with pkgs; [
e2fsprogs # ext4
btrfs-progs
mtdutils # mtd, jffs2, ubifs
dtc # you never know when you might need device tree stuff
util-linux-small # fdisk
libubootenv # fw_{set,print}env
pciutils
];
}

View File

@ -43,8 +43,13 @@ in rec {
../modules/bridge
../modules/ntp
../modules/ssh
../modules/outputs/btrfs.nix
../modules/outputs/extlinux.nix
];
hostname = "rotuer";
rootfsType = "btrfs";
rootOptions = "subvol=@";
boot.loader.extlinux.enable = true;
services.hostap = svc.hostapd.build {
interface = config.hardware.networkInterfaces.wlan;

View File

@ -40,12 +40,18 @@ in {
rootfsType = mkOption {
default = "squashfs";
type = types.enum [
"btrfs"
"ext4"
"jffs2"
"squashfs"
"ubifs"
];
};
rootOptions = mkOption {
type = types.nullOr types.str;
default = null;
};
boot = {
commandLine = mkOption {
type = types.listOf types.nonEmptyStr;
@ -94,7 +100,8 @@ in {
"root=${config.hardware.rootDevice}"
"rootfstype=${config.rootfsType}"
"fw_devlink=off"
];
] ++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}";
users.root = {
uid = 0; gid= 0; gecos = "Root of all evaluation";
dir = "/home/root/";
@ -134,6 +141,7 @@ in {
proc = dir {};
run = dir {};
sys = dir {};
tmp = dir {};
};
};
}

37
modules/outputs/btrfs.nix Normal file
View File

@ -0,0 +1,37 @@
{
config
, pkgs
, lib
, ...
}:
let
inherit (lib) mkIf mkOption types;
o = config.system.outputs;
in
{
imports = [
./initramfs.nix
];
config = mkIf (config.rootfsType == "btrfs") {
kernel.config = {
BTRFS_FS = "y";
};
boot.initramfs.enable = true;
system.outputs = {
rootfs =
let
inherit (pkgs.pkgsBuildBuild) runCommand e2fsprogs;
in runCommand "mkfs.btrfs" {
depsBuildBuild = [ e2fsprogs ];
} ''
tree=${o.bootablerootdir}
size=$(du -s --apparent-size --block-size 1024 $tree |cut -f1)
# add 25% for filesystem overhead
size=$(( 5 * $size / 4))
dd if=/dev/zero of=$out bs=1024 count=$size
echo "not implemented" ; exit 1
# mke2fs -t ext4 -j -d $tree $out
'';
};
};
}

View File

@ -6,6 +6,7 @@
}:
let
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
inherit (pkgs.pseudofile) dir symlink;
cfg = config.boot.loader.extlinux;
o = config.system.outputs;
cmdline = concatStringsSep " " config.boot.commandLine;
@ -17,7 +18,7 @@ in {
};
options.boot.loader.extlinux.enable = mkEnableOption "extlinux";
config = { # mkIf cfg.enable {
config = mkIf cfg.enable {
system.outputs.extlinux = pkgs.runCommand "extlinux" {} ''
mkdir $out
cd $out
@ -27,13 +28,16 @@ in {
mkdir extlinux
cat > extlinux/extlinux.conf << _EOF
menu title Liminix
timeout 100
timeout 40
label Liminix
kernel /boot/kernel
# initrd /boot/initramfs
append ${cmdline} root=/dev/vda1
append ${cmdline}
${if wantsDtb then "fdt /boot/dtb" else ""}
_EOF
'';
filesystem = dir {
boot = symlink config.system.outputs.extlinux;
};
};
}

View File

@ -17,6 +17,7 @@ shift
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp
# s6-linux-init mounts /dev before this script is called
mkdir /dev/pts
mount -t devpts none /dev/pts

View File

@ -0,0 +1,19 @@
{ config, pkgs, lib, ... } :
{
config = {
programs.busybox = {
options = {
# schnapps is a shell script that needs
# [ command
# find -maxdepth -mindepth
# head -c
# echo -n
ASH_TEST = "y";
FEATURE_FIND_MAXDEPTH = "y";
FEATURE_FANCY_HEAD = "y";
FEATURE_FANCY_ECHO = "y";
};
};
defaultProfile.packages = [ pkgs.schnapps ] ;
};
}

View File

@ -50,6 +50,12 @@ extraPkgs // {
};
# keep these alphabetical
btrfs-progs = prev.btrfs-progs.override {
udevSupport = false;
udev = null;
};
chrony =
let chrony' = prev.chrony.overrideAttrs(o: {
configureFlags = [

View File

@ -10,10 +10,7 @@ let
type' = types.submodule { options = type; };
in (mergeDefinitions [] type' defs).mergedValue;
in {
pseudofile = callPackage ./pseudofile {};
liminix = {
services = callPackage ./liminix-tools/services {};
networking = callPackage ./liminix-tools/networking {};
builders = {
squashfs = callPackage ./liminix-tools/builders/squashfs.nix {};
dtb = callPackage ./kernel/dtb.nix {};
@ -52,32 +49,26 @@ in {
};
inherit typeChecked;
};
networking = callPackage ./liminix-tools/networking {};
services = callPackage ./liminix-tools/services {};
};
writeFennelScript = callPackage ./write-fennel-script {};
writeFennel = callPackage ./write-fennel {};
writeAshScript = callPackage ./write-ash-script {};
systemconfig = callPackage ./systemconfig {};
s6-init-bin = callPackage ./s6-init-bin {};
s6-rc-database = callPackage ./s6-rc-database {};
run-liminix-vm = callPackage ./run-liminix-vm {};
ppp = callPackage ./ppp {};
pppoe = callPackage ./pppoe {};
kernel-backport = callPackage ./kernel-backport {};
mac80211 = callPackage ./mac80211 {};
netlink-lua = callPackage ./netlink-lua {};
linotify = callPackage ./linotify {};
ifwait = callPackage ./ifwait {};
# please keep the rest of this list alphabetised :-)
anoia = callPackage ./anoia {};
fennel = callPackage ./fennel {};
fennelrepl = callPackage ./fennelrepl {};
firewallgen = callPackage ./firewallgen {};
gen_init_cpio = callPackage ./gen_init_cpio {};
serviceFns = callPackage ./service-fns {};
# these are packages for the build system not the host/target
tufted = callPackage ./tufted {};
routeros = callPackage ./routeros {};
go-l2tp = callPackage ./go-l2tp {};
hi = callPackage ./hi {};
ifwait = callPackage ./ifwait {};
initramfs-peek = callPackage ./initramfs-peek {};
kernel-backport = callPackage ./kernel-backport {};
kernel-modules = callPackage ./kernel-modules {};
levitate = callPackage ./levitate {};
libubootenv = callPackage ./libubootenv {};
linotify = callPackage ./linotify {};
# we need to build real lzma instead of using xz, because the lzma
# decoder in u-boot doesn't understand streaming lzma archives
@ -86,24 +77,33 @@ in {
# https://sourceforge.net/p/squashfs/mailman/message/26599379/
lzma = callPackage ./lzma {};
preinit = callPackage ./preinit {};
swconfig = callPackage ./swconfig {};
odhcp6c = callPackage ./odhcp6c {};
openwrt = callPackage ./openwrt {};
initramfs-peek = callPackage ./initramfs-peek {};
mac80211 = callPackage ./mac80211 {};
min-collect-garbage = callPackage ./min-collect-garbage {};
min-copy-closure = callPackage ./min-copy-closure {};
hi = callPackage ./hi {};
firewallgen = callPackage ./firewallgen {};
kernel-modules = callPackage ./kernel-modules {};
netlink-lua = callPackage ./netlink-lua {};
odhcp-script = callPackage ./odhcp-script {};
fennel = callPackage ./fennel {};
fennelrepl = callPackage ./fennelrepl {};
anoia = callPackage ./anoia {};
odhcp6c = callPackage ./odhcp6c {};
openwrt = callPackage ./openwrt {};
ppp = callPackage ./ppp {};
pppoe = callPackage ./pppoe {};
preinit = callPackage ./preinit {};
pseudofile = callPackage ./pseudofile {};
routeros = callPackage ./routeros {};
run-liminix-vm = callPackage ./run-liminix-vm {};
s6-init-bin = callPackage ./s6-init-bin {};
s6-rc-database = callPackage ./s6-rc-database {};
levitate = callPackage ./levitate {};
# schnapps is written by Turris and provides a high-level interface
# to btrfs snapshots. It may be useful on the Turris Omnia to
# install Liminix while retaining the ability to rollback to the
# vendor OS, or even to derisk Liminix updates on that device
schnapps = callPackage ./schnapps {};
libubootenv = callPackage ./libubootenv {};
serviceFns = callPackage ./service-fns {};
swconfig = callPackage ./swconfig {};
systemconfig = callPackage ./systemconfig {};
tufted = callPackage ./tufted {};
writeAshScript = callPackage ./write-ash-script {};
writeFennel = callPackage ./write-fennel {};
writeFennelScript = callPackage ./write-fennel-script {};
}

View File

@ -12,7 +12,7 @@ target_host=$1
shift
if [ -z "$target_host" ] ; then
echo Usage: liminix-rebuild [--no-reboot] target-host params
echo Usage: liminix-rebuild \[--no-reboot\] target-host params
exit 1
fi

View File

@ -7,8 +7,8 @@ let
name = "openwrt-source";
repo = "openwrt";
owner = "openwrt";
rev = "a5265497a4f6da158e95d6a450cb2cb6dc085cab";
hash = "sha256-YYi4gkpLjbOK7bM2MGQjAyEBuXJ9JNXoz/JEmYf8xE8=";
rev = "refs/tags/v23.05.2";
hash = "sha256-kP+cSOB6LiOMWs7g+ji7P7ehiDYDwRdmT4R5jSzw6K4=";
};
doPatch = family : ''
cp -av ${src}/target/linux/generic/files/* .

7
pkgs/preinit/opts.h Normal file
View File

@ -0,0 +1,7 @@
struct root_opts {
char *device;
char *fstype;
char *mount_opts;
};
void parseopts(char * cmdline, struct root_opts *opts);

View File

@ -3,6 +3,9 @@
#include <string.h>
#include <unistd.h>
#include "opts.h"
static int begins_with(char * str, char * prefix)
{
while(*prefix) {
@ -36,34 +39,37 @@ char * pr_u32(int32_t input) {
i+=2;
buf[i] ='\0';
write(2, buf, i);
return buf;
if(write(2, buf, i))
return buf;
else
return NULL;
}
static char *eat_word(char *p)
{
while(*p && (*p != ' ')) p++;
void parseopts(char * cmdline, char **root, char **rootfstype) {
*root = 0;
*rootfstype = 0;
if(*p) {
*p = '\0';
p++;
};
return p;
}
static char * eat_param(char *p, char *param_name, char **out)
{
if(begins_with(p, param_name)) {
*out = p + strlen(param_name);
p = eat_word(p);
};
return p;
}
void parseopts(char * cmdline, struct root_opts *opts) {
for(char *p = cmdline; *p; p++) {
if(begins_with(p, "root=")) {
*root = p + strlen("root=");
while(*p && (*p != ' ')) p++;
if(*p) {
*p = '\0';
p++;
};
};
if(begins_with(p, "rootfstype=")) {
*rootfstype = p + strlen("rootfstype=");
while(*p && (*p != ' ')) p++;
if(*p) {
*p = '\0';
p++;
};
};
p = eat_param(p, "root=", &(opts->device));
p = eat_param(p, "rootfstype=", &(opts->fstype));
p = eat_param(p, "rootflags=", &(opts->mount_opts));
};
}
@ -82,45 +88,59 @@ void parseopts(char * cmdline, char **root, char **rootfstype) {
int main()
{
char * root = "/dev/hda1";
char * rootfstype = "xiafs";
struct root_opts opts = {
.device = "/dev/hda1",
.fstype = "xiafs",
.mount_opts = NULL
};
char *buf;
// finds root= and rootfstype= options
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 foo");
parseopts(buf, &root, &rootfstype);
expect_equal(root, "/dev/mtdblock0");
expect_equal(rootfstype, "ubifs");
// finds root= rootfstype= rootflags= 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 foo");
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
expect_equal(opts.device, "/dev/mtdblock0");
expect_equal(opts.fstype, "ubifs");
expect_equal(opts.mount_opts, "subvol=1");
// in case of duplicates, chooses the latter
// 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");
parseopts(buf, &root, &rootfstype);
expect_equal(root, "/dev/mtdblock0");
expect_equal(rootfstype, "ubifs");
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
expect_equal(opts.device, "/dev/mtdblock0");
expect_equal(opts.fstype, "ubifs");
// options may appear in either order
buf = strdup("liminix fw_devlink=off root=/dev/hda1 rootfstype=ubifs foo");
parseopts(buf, &root, &rootfstype);
expect_equal(root, "/dev/hda1");
expect_equal(rootfstype, "ubifs");
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
expect_equal(opts.device, "/dev/hda1");
expect_equal(opts.fstype, "ubifs");
// works when rootflags is the last option
buf = strdup("liminix fw_devlink=off root=/dev/hda1 rootfstype=ubifs rootflags=subvol=@");
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
expect_equal(opts.device, "/dev/hda1");
expect_equal(opts.fstype, "ubifs");
expect_equal(opts.mount_opts, "subvol=@");
buf = strdup("liminix rootfstype=ubifs fw_devlink=off root=/dev/hda1 foo");
parseopts(buf, &root, &rootfstype);
expect_equal(rootfstype, "ubifs");
expect_equal(root, "/dev/hda1");
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
expect_equal(opts.fstype, "ubifs");
expect_equal(opts.device, "/dev/hda1");
// provides NULL for missing options
buf = strdup("liminix rufustype=ubifs fw_devlink=off foot=/dev/hda1");
parseopts(buf, &root, &rootfstype);
if(rootfstype) die("expected null rootfstype, got \"%s\"", rootfstype);
if(root) die("expected null root, got \"%s\"", root);
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
if(opts.fstype) die("expected null rootfstype, got \"%s\"", opts.fstype);
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);
// provides empty strings for empty options
buf = strdup("liminix rootfstype= fw_devlink=off root= /dev/hda1");
parseopts(buf, &root, &rootfstype);
if(strlen(rootfstype)) die("expected empty rootfstype, got \"%s\"", rootfstype);
if(strlen(root)) die("expected null root, got \"%s\"", root);
memset(&opts, '\0', sizeof opts); parseopts(buf, &opts);
if(strlen(opts.fstype)) die("expected empty rootfstype, got \"%s\"", opts.fstype);
if(strlen(opts.device)) die("expected null root, got \"%s\"", opts.device);
expect_equal("01", pr_u32(1));
expect_equal("ab", pr_u32(0xab));

View File

@ -10,7 +10,7 @@
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
void parseopts(char * cmdline, char **root, char **rootfstype);
#include "opts.h"
#define ERR(x) write(2, x, strlen(x))
#define AVER(c) do { if(c < 0) { ERR("failed: " #c ": error=0x" ); pr_u32(errno); ERR("\n"); } } while(0)
@ -49,8 +49,11 @@ char buf[COMMAND_LINE_SIZE];
int main(int argc, char *argv[], char *envp[])
{
char *rootdevice = 0;
char *rootfstype = 0;
struct root_opts opts = {
.device = NULL,
.fstype = NULL,
.mount_opts = NULL
};
write(1, banner, strlen(banner));
@ -73,16 +76,20 @@ int main(int argc, char *argv[], char *envp[])
ERR("failed: open(\"/proc/cmdline\")\n");
die();
}
parseopts(buf, &rootdevice, &rootfstype);
parseopts(buf, &opts);
if(rootdevice) {
if(!rootfstype) rootfstype = "jffs2"; /* backward compatibility */
if(opts.device) {
if(!opts.fstype) opts.fstype = "jffs2"; /* backward compatibility */
write(1, "rootdevice ", 11);
write(1, rootdevice, strlen(rootdevice));
write(1, opts.device, strlen(opts.device));
write(1, " (", 2);
write(1, rootfstype, strlen(rootfstype));
write(1, opts.fstype, strlen(opts.fstype));
if(opts.mount_opts) {
write(1, ", opts=", 7);
write(1, opts.mount_opts, strlen(opts.mount_opts));
}
write(1, ")\n", 2);
AVER(mount(rootdevice, "/target/persist", rootfstype, 0, NULL));
AVER(mount(opts.device, "/target/persist", opts.fstype, 0, opts.mount_opts));
AVER(mount("/target/persist/nix", "/target/nix",
"bind", MS_BIND, NULL));

27
pkgs/schnapps/default.nix Normal file
View File

@ -0,0 +1,27 @@
{
stdenv
, fetchFromGitLab
, makeWrapper
, btrfs-progs
, lib
}:
let search_path = lib.makeBinPath [btrfs-progs];
in stdenv.mkDerivation {
pname = "schnapps";
version = "2.13.0";
src =fetchFromGitLab {
domain = "gitlab.nic.cz";
owner = "turris";
repo = "schnapps";
rev = "53ac92c765d670be4b98dba2c948859a9ac7607f";
hash = "sha256-yVgXK+V2wrcOPLB6X6qm3hyBcWcyzNhfJjFF7YRk5Lc=";
};
nativeBuildInputs = [ makeWrapper ];
buildPhase = ":";
installPhase = ''
install -D schnapps.sh $out/bin/schnapps
wrapProgram $out/bin/schnapps --prefix PATH : "${search_path}"
'';
}

View File

@ -81,8 +81,22 @@ in attrset:
$STRIP --remove-section=.note --remove-section=.comment --strip-all makedevs -o $out/bin/activate
ln -s ${s6-init-bin}/bin/init $out/bin/init
cat > $out/bin/install <<EOF
#!/bin/sh
cp -v -fP $out/bin/* $out/etc/* \''${1-/}/persist
#!/bin/sh -e
prefix=\''${1-/}
src=\''${prefix}$out
dest=\$prefix
${# if we are running on a normal mounted system then
# the actual device root is mounted on /persist
# and /nix is bind mounted from /persist/nix
# (see the code in preinit). So we need to check for this
# case otherwise we will install into a ramfs/rootfs
""
}
if test -d $dest/persist; then dest=$dest/persist; fi
cp -v -fP \$src/bin/* \$src/etc/* \$dest
${if attrset ? boot then ''
(cd \$dest && rm ./boot && ln -sf ${lib.strings.removePrefix "/" attrset.boot.target} ./boot)
'' else ""}
EOF
chmod +x $out/bin/install
'';