generate a mips squashfs with some s6-rc services

haven't even tried booting it but I don't expect it to work. Needs

- s6-linux-init or some other pid 1 program
- a kernel
module-based-network
Daniel Barlow 2022-09-19 23:51:38 +01:00
commit 4b118bca19
7 changed files with 223 additions and 0 deletions

21
default.nix Normal file
View File

@ -0,0 +1,21 @@
{ device ? (import devices/gl-ar750.nix)
}:
let
overlay = import ./overlay.nix;
nixpkgs = import <nixpkgs> ( device.system // {overlays = [overlay]; });
config = (import <liminix-config>) {
config = {
systemPackages = [];
services = {};
};
tools = nixpkgs.pkgs.callPackage ./tools {};
inherit (nixpkgs) pkgs;
};
finalConfig = config // {
packages = (with nixpkgs.pkgs; [ s6-rc ]) ++
config.systemPackages ++
(builtins.attrValues config.services)
;
};
in (import ./make-image.nix) nixpkgs finalConfig

11
devices/gl-ar750.nix Normal file
View File

@ -0,0 +1,11 @@
{
system = {
crossSystem = {
config = "mips-unknown-linux-musl";
gcc = {
abi = "32";
arch = "mips32"; # maybe mips_24kc-
};
};
};
}

57
example-configuration.nix Normal file
View File

@ -0,0 +1,57 @@
{ config, tools, pkgs } :
let
inherit (tools.networking) interface address udhcpc odhcpc;
inherit (tools.services) oneshot longrun bundle output;
in rec {
services.loopback =
let iface = interface { type = "loopback"; device = "lo";};
in bundle {
name = "loopback";
contents = [
(address iface { family = "inet4"; addr ="127.0.0.1";})
(address iface { family = "inet6"; addr ="::1";})
];
};
services.dhcpv4 =
let iface = interface { type = "hardware"; device = "eth0"; };
in udhcpc iface {};
services.dhcpv6 =
let iface = interface { type = "hardware"; device = "eth0"; };
in odhcpc iface { uid = "e7"; };
services.ntp = longrun {
# the simplest approach at the consumer end is to require the
# producer to create a file per output variable.
name = "ntp";
run = let s = services;
r = "${pkgs.ntp}/bin/ntp $(cat ${output s.dhcpv4 "ntp_servers"}) $(cat ${output s.dhcpv6 "NTP_IP"})";
in (builtins.trace r r);
# I don't think it's possible to standardise the file names
# generally, as different services have different outputs, but it
# would be cool if services that provide an interface could use
# the same name as each other. e.g. for anything implementing
# addressProvider you might expect (output svc "address") or
# (output svc "family") to work. Otherwise switching a network link
# from static to dhcp might require reviewing all the downstreams
# that refer to it.
# Also, services should declare the outputs they provide
outputs = [];
dependencies = [services.dhcpv4];
};
services.defaultroute4 =
let s = services;
in oneshot {
name = "defaultroute4";
up = ''
ip route add default gw $(cat ${output s.dhcpv4 "address"})
echo "1" > /sys/net/ipv4/$(cat ${output s.dhcpv4 "ifname"})
'';
down = ''
ip route del default gw $(cat ${output s.dhcpv4 "address"})
echo "0" > /sys/net/ipv4/$(cat ${output s.dhcpv4 "ifname"})
'';
};
systemPackages = [ pkgs.hello ] ;
}

35
make-image.nix Normal file
View File

@ -0,0 +1,35 @@
pkgs: config:
let
inherit (pkgs) buildPlatform callPackage runCommandNoCC closureInfo stdenv writeText s6-rc;
# we need to generate s6 db, by generating closure of all
# config.services and calling s6-rc-compile on them
allServices = closureInfo {
rootPaths = builtins.attrValues config.services;
};
s6db = stdenv.mkDerivation {
name = "make-s6-db";
nativeBuildInputs = [pkgs.buildPackages.s6-rc];
builder = writeText "find-s6-services" ''
source $stdenv/setup
mkdir -p $out
srcs=""
shopt -s nullglob
for i in $(cat ${allServices}/store-paths ); do
if test -d $i; then
for j in $i/* ; do
if test -f $j/type ; then
srcs="$srcs $i"
fi
done
fi
done
echo s6-rc-compile $out/compiled $srcs
s6-rc-compile $out/compiled $srcs
'';
};
makeSquashfs = callPackage <nixpkgs/nixos/lib/make-squashfs.nix> {
storeContents = [ s6db ] ++ config.packages ;
# comp = "xz -Xdict-size 100%"
};
in makeSquashfs

3
overlay.nix Normal file
View File

@ -0,0 +1,3 @@
final: prev: {
# s6-rc = final.callPackage ./pkgs/s6-rc;
}

16
tools/builder.sh Normal file
View File

@ -0,0 +1,16 @@
source $stdenv/setup
mkdir -p $out/${name}
echo $type > $out/${name}/type
mkdir -p $out/${name}/dependencies.d
echo $buildInputs > $out/buildInputs
test -n "$dependencies" && for d in "$dependencies"; do
touch $out/${name}/dependencies.d/$d
done
test -n "$contents" && for d in "$contents"; do
mkdir -p $out/${name}/contents.d
touch $out/${name}/contents.d/$d
done
test -n "$run" && (echo "$run" > $out/${name}/run)
test -n "$up" && (echo "$up" > $out/${name}/up)
test -n "$down" && (echo "$down" > $out/${name}/down)
(echo $out/${name} && cd $out/${name} && find . -ls)

80
tools/default.nix Normal file
View File

@ -0,0 +1,80 @@
{
stdenvNoCC
, s6-rc
} :let
inherit (builtins) concatStringsSep;
longrun = {
name
, run
, outputs ? []
, dependencies ? []
} @ args: stdenvNoCC.mkDerivation {
name = "${name}.service";
type = "longrun";
buildInputs = dependencies;
dependencies = builtins.map (d: d.name) dependencies;
inherit run;
builder = ./builder.sh;
};
oneshot = {
name
, up
, down
, outputs ? []
, dependencies ? []
, ...
} @ args: stdenvNoCC.mkDerivation {
# stdenvNoCC is to avoid generating derivations with names
# like foo.service-mips-linux-musl
name = "${name}.service";
type = "oneshot";
# does this suffice to make sure dependencies are included
# even though the built output has no references to their
# store directories?
buildInputs = dependencies;
inherit up down;
dependencies = builtins.map (d: d.name) dependencies;
builder = ./builder.sh;
};
bundle = {
name
, contents ? []
, dependencies ? []
, ...
}: stdenvNoCC.mkDerivation {
name = "${name}.bundle";
type = "bundle";
contents = builtins.map (d: d.name) contents;
buildInputs = dependencies ++ contents;
dependencies = builtins.map (d: d.name) dependencies;
builder = ./builder.sh;
};
in {
networking = {
interface = { type, device } @ args: oneshot {
name = "${device}.link";
up = "ip link set up dev ${device}";
down = "ip link set down dev ${device}";
} // {
inherit device;
};
address = interface: { family, addr } @ args: oneshot {
dependencies = [ interface ];
name = "${interface.device}.addr.${addr}";
up = "ip address add ${addr} dev ${interface.device} ";
down = "ip address del ${addr} dev ${interface.device} ";
};
udhcpc = interface: { ... } @ args: longrun {
name = "${interface.device}.udhcp";
run = "udhchpcd ${interface.device}";
};
odhcpc = interface: { ... } @ args: longrun {
name = "${interface.device}.odhcp";
run = "odhcpcd ${interface.device}";
};
};
services = {
inherit longrun oneshot bundle;
output = service: name: "/run/services/outputs/${service.name}/${name}";
};
}