nixfmt-rfc-style
There is nothing in this commit except for the changes made by nix-shell -p nixfmt-rfc-style --run "nixfmt ." If this has mucked up your open branches then sorry about that. You can probably nixfmt them to match before merging
This commit is contained in:
@@ -4,35 +4,35 @@
|
||||
|
||||
{
|
||||
imports = [
|
||||
./base.nix
|
||||
./bridge
|
||||
./busybox.nix
|
||||
./dhcp6c
|
||||
./dnsmasq
|
||||
./firewall
|
||||
./hardware.nix
|
||||
./hostapd
|
||||
./hostname.nix
|
||||
./kernel
|
||||
./mdevd.nix
|
||||
./mount
|
||||
./network
|
||||
./ntp
|
||||
./outputs.nix
|
||||
./outputs/ext4fs.nix
|
||||
./outputs/initramfs.nix
|
||||
./outputs/jffs2.nix
|
||||
./outputs/mtdimage.nix
|
||||
./outputs/tftpboot.nix
|
||||
./outputs/ubifs.nix
|
||||
./outputs/ubimage.nix
|
||||
./outputs/vmroot.nix
|
||||
./ppp
|
||||
./ramdisk.nix
|
||||
./ssh
|
||||
./users.nix
|
||||
./vlan
|
||||
./watchdog
|
||||
./wlan.nix
|
||||
];
|
||||
./base.nix
|
||||
./bridge
|
||||
./busybox.nix
|
||||
./dhcp6c
|
||||
./dnsmasq
|
||||
./firewall
|
||||
./hardware.nix
|
||||
./hostapd
|
||||
./hostname.nix
|
||||
./kernel
|
||||
./mdevd.nix
|
||||
./mount
|
||||
./network
|
||||
./ntp
|
||||
./outputs.nix
|
||||
./outputs/ext4fs.nix
|
||||
./outputs/initramfs.nix
|
||||
./outputs/jffs2.nix
|
||||
./outputs/mtdimage.nix
|
||||
./outputs/tftpboot.nix
|
||||
./outputs/ubifs.nix
|
||||
./outputs/ubimage.nix
|
||||
./outputs/vmroot.nix
|
||||
./ppp
|
||||
./ramdisk.nix
|
||||
./ssh
|
||||
./users.nix
|
||||
./vlan
|
||||
./watchdog
|
||||
./wlan.nix
|
||||
];
|
||||
}
|
||||
|
@@ -1,12 +1,17 @@
|
||||
{ lim, pkgs, config, ...}:
|
||||
{
|
||||
lim,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
config = {
|
||||
kernel.config = {
|
||||
CPU_LITTLE_ENDIAN= "y";
|
||||
CPU_BIG_ENDIAN= "n";
|
||||
CPU_LITTLE_ENDIAN = "y";
|
||||
CPU_BIG_ENDIAN = "n";
|
||||
# CMDLINE_FROM_BOOTLOADER availability is conditional
|
||||
# on CMDLINE being set to something non-empty
|
||||
CMDLINE="\"empty=false\"";
|
||||
CMDLINE = "\"empty=false\"";
|
||||
CMDLINE_FROM_BOOTLOADER = "y";
|
||||
|
||||
OF = "y";
|
||||
|
@@ -1,10 +1,15 @@
|
||||
{ lim, pkgs, config, ...}:
|
||||
{
|
||||
lim,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
{
|
||||
config = {
|
||||
kernel.config = {
|
||||
OF = "y";
|
||||
};
|
||||
kernel.makeTargets = ["arch/arm/boot/zImage"];
|
||||
kernel.makeTargets = [ "arch/arm/boot/zImage" ];
|
||||
hardware.ram.startAddress = lim.parseInt "0x40000000";
|
||||
system.outputs.u-boot = pkgs.ubootQemuArm;
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ config, lim, ...}:
|
||||
{ config, lim, ... }:
|
||||
{
|
||||
config = {
|
||||
kernel.config = {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ pkgs, config, ...}:
|
||||
{ pkgs, config, ... }:
|
||||
{
|
||||
imports = [ ./mips.nix ];
|
||||
config = {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ config, ...}:
|
||||
{ config, ... }:
|
||||
{
|
||||
imports = [ ./mips.nix ];
|
||||
config = {
|
||||
|
119
modules/base.nix
119
modules/base.nix
@@ -1,15 +1,20 @@
|
||||
## Base options
|
||||
## ============
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
|
||||
type_service = pkgs.liminix.lib.types.service;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
defaultProfile = {
|
||||
packages = mkOption {
|
||||
@@ -109,8 +114,13 @@ in {
|
||||
};
|
||||
};
|
||||
config = {
|
||||
defaultProfile.packages = with pkgs;
|
||||
[ s6 s6-init-bin execline s6-linux-init s6-rc ];
|
||||
defaultProfile.packages = with pkgs; [
|
||||
s6
|
||||
s6-init-bin
|
||||
execline
|
||||
s6-linux-init
|
||||
s6-rc
|
||||
];
|
||||
|
||||
boot.commandLine = [
|
||||
"panic=10 oops=panic init=/bin/init loglevel=8"
|
||||
@@ -119,69 +129,98 @@ in {
|
||||
"fw_devlink=off"
|
||||
] ++ lib.optional (config.rootOptions != null) "rootflags=${config.rootOptions}";
|
||||
|
||||
system.callService = path : parameters :
|
||||
system.callService =
|
||||
path: parameters:
|
||||
let
|
||||
typeChecked = caller: type: value:
|
||||
typeChecked =
|
||||
caller: type: value:
|
||||
let
|
||||
inherit (lib) types mergeDefinitions;
|
||||
defs = [{ file = caller; inherit value; }];
|
||||
defs = [
|
||||
{
|
||||
file = caller;
|
||||
inherit value;
|
||||
}
|
||||
];
|
||||
type' = types.submodule { options = type; };
|
||||
in (mergeDefinitions [] type' defs).mergedValue;
|
||||
cp = lib.callPackageWith(pkgs // { svc = config.system.service; });
|
||||
pkg = cp path {};
|
||||
checkTypes = t : p : typeChecked (builtins.toString path) t p;
|
||||
in {
|
||||
in
|
||||
(mergeDefinitions [ ] type' defs).mergedValue;
|
||||
cp = lib.callPackageWith (pkgs // { svc = config.system.service; });
|
||||
pkg = cp path { };
|
||||
checkTypes = t: p: typeChecked (builtins.toString path) t p;
|
||||
in
|
||||
{
|
||||
inherit parameters;
|
||||
build = { dependencies ? [], ... } @ args :
|
||||
build =
|
||||
{
|
||||
dependencies ? [ ],
|
||||
...
|
||||
}@args:
|
||||
let
|
||||
s = pkg (checkTypes parameters
|
||||
(builtins.removeAttrs args ["dependencies"]));
|
||||
in s.overrideAttrs (o: {
|
||||
s = pkg (checkTypes parameters (builtins.removeAttrs args [ "dependencies" ]));
|
||||
in
|
||||
s.overrideAttrs (o: {
|
||||
dependencies = dependencies ++ o.dependencies;
|
||||
buildInputs = dependencies ++ o.buildInputs;
|
||||
});
|
||||
};
|
||||
|
||||
users.root = {
|
||||
uid = 0; gid= 0; gecos = "Root of all evaluation";
|
||||
uid = 0;
|
||||
gid = 0;
|
||||
gecos = "Root of all evaluation";
|
||||
dir = "/home/root/";
|
||||
passwd = lib.mkDefault "";
|
||||
shell = "/bin/sh";
|
||||
};
|
||||
groups = {
|
||||
root = {
|
||||
gid = 0; usernames = ["root"];
|
||||
gid = 0;
|
||||
usernames = [ "root" ];
|
||||
};
|
||||
system = {
|
||||
gid = 1; usernames = ["root"];
|
||||
gid = 1;
|
||||
usernames = [ "root" ];
|
||||
};
|
||||
};
|
||||
|
||||
filesystem = dir {
|
||||
dev =
|
||||
let node = type: major: minor: mode : { inherit type major minor mode; };
|
||||
in dir {
|
||||
null = node "c" "1" "3" "0666";
|
||||
zero = node "c" "1" "5" "0666";
|
||||
tty = node "c" "5" "0" "0666";
|
||||
let
|
||||
node = type: major: minor: mode: {
|
||||
inherit
|
||||
type
|
||||
major
|
||||
minor
|
||||
mode
|
||||
;
|
||||
};
|
||||
in
|
||||
dir {
|
||||
null = node "c" "1" "3" "0666";
|
||||
zero = node "c" "1" "5" "0666";
|
||||
tty = node "c" "5" "0" "0666";
|
||||
console = node "c" "5" "1" "0600";
|
||||
pts = dir {};
|
||||
pts = dir { };
|
||||
};
|
||||
etc =
|
||||
let
|
||||
profile = symlink (
|
||||
pkgs.writeScript ".profile" ''
|
||||
PATH=${lib.makeBinPath config.defaultProfile.packages}:/bin
|
||||
export PATH
|
||||
''
|
||||
);
|
||||
in
|
||||
dir {
|
||||
inherit profile;
|
||||
ashrc = profile;
|
||||
};
|
||||
etc = let
|
||||
profile = symlink
|
||||
(pkgs.writeScript ".profile" ''
|
||||
PATH=${lib.makeBinPath config.defaultProfile.packages}:/bin
|
||||
export PATH
|
||||
'');
|
||||
in dir {
|
||||
inherit profile;
|
||||
ashrc = profile;
|
||||
};
|
||||
|
||||
proc = dir {};
|
||||
run = dir {};
|
||||
sys = dir {};
|
||||
tmp = dir {};
|
||||
proc = dir { };
|
||||
run = dir { };
|
||||
sys = dir { };
|
||||
tmp = dir { };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -6,8 +6,12 @@
|
||||
## with one or more WLANs so that several local devices appear to be
|
||||
## on the same network.
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
@@ -40,13 +44,15 @@ in
|
||||
};
|
||||
};
|
||||
};
|
||||
config.kernel.config = {
|
||||
BRIDGE = "y";
|
||||
BRIDGE_IGMP_SNOOPING = "y";
|
||||
} // lib.optionalAttrs (config.system.service ? vlan) {
|
||||
# depends on bridge _and_ vlan. I would like there to be
|
||||
# a better way to test for the existence of vlan config:
|
||||
# maybe the module should set an `enabled` attribute?
|
||||
BRIDGE_VLAN_FILTERING = "y";
|
||||
};
|
||||
config.kernel.config =
|
||||
{
|
||||
BRIDGE = "y";
|
||||
BRIDGE_IGMP_SNOOPING = "y";
|
||||
}
|
||||
// lib.optionalAttrs (config.system.service ? vlan) {
|
||||
# depends on bridge _and_ vlan. I would like there to be
|
||||
# a better way to test for the existence of vlan config:
|
||||
# maybe the module should set an `enabled` attribute?
|
||||
BRIDGE_VLAN_FILTERING = "y";
|
||||
};
|
||||
}
|
||||
|
@@ -1,21 +1,25 @@
|
||||
{
|
||||
liminix
|
||||
, ifwait
|
||||
, svc
|
||||
liminix,
|
||||
ifwait,
|
||||
svc,
|
||||
}:
|
||||
{ members, primary } :
|
||||
{ members, primary }:
|
||||
|
||||
let
|
||||
inherit (liminix.networking) interface;
|
||||
inherit (liminix.services) bundle oneshot;
|
||||
addif = member :
|
||||
addif =
|
||||
member:
|
||||
# how do we get sight of services from here? maybe we need to
|
||||
# implement ifwait as a regualr derivation instead of a
|
||||
# servicedefinition
|
||||
svc.ifwait.build {
|
||||
state = "running";
|
||||
interface = member;
|
||||
dependencies = [ primary member ];
|
||||
dependencies = [
|
||||
primary
|
||||
member
|
||||
];
|
||||
service = oneshot {
|
||||
name = "${primary.name}.member.${member.name}";
|
||||
up = ''
|
||||
@@ -24,7 +28,8 @@ let
|
||||
down = "ip link set dev $(output ${member} ifname) nomaster";
|
||||
};
|
||||
};
|
||||
in bundle {
|
||||
in
|
||||
bundle {
|
||||
name = "${primary.name}.members";
|
||||
contents = map addif members;
|
||||
}
|
||||
|
@@ -1,11 +1,12 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
liminix,
|
||||
lib,
|
||||
}:
|
||||
{ ifname } :
|
||||
{ ifname }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
in oneshot rec {
|
||||
in
|
||||
oneshot rec {
|
||||
name = "${ifname}.link";
|
||||
up = ''
|
||||
ip link add name ${ifname} type bridge
|
||||
|
@@ -6,19 +6,26 @@
|
||||
## the commands (termed "applets") required by the user or
|
||||
## by other included modules.
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types mapAttrsToList;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (lib.strings) toUpper;
|
||||
|
||||
attrs = { options, applets } :
|
||||
attrs =
|
||||
{ options, applets }:
|
||||
let
|
||||
extraOptions = builtins.concatStringsSep "\n"
|
||||
(mapAttrsToList (n: v: "CONFIG_${toUpper n} ${toString v}") options);
|
||||
appletOptions = builtins.concatStringsSep "\n"
|
||||
(map (n: "CONFIG_${toUpper n} y") applets);
|
||||
in {
|
||||
extraOptions = builtins.concatStringsSep "\n" (
|
||||
mapAttrsToList (n: v: "CONFIG_${toUpper n} ${toString v}") options
|
||||
);
|
||||
appletOptions = builtins.concatStringsSep "\n" (map (n: "CONFIG_${toUpper n} y") applets);
|
||||
in
|
||||
{
|
||||
enableMinimal = true;
|
||||
extraConfig = ''
|
||||
${extraOptions}
|
||||
@@ -26,44 +33,171 @@ let
|
||||
'';
|
||||
};
|
||||
cfg = config.programs.busybox;
|
||||
busybox = pkgs.busybox.override (attrs { inherit (cfg) applets options; });
|
||||
makeLinks = lib.attrsets.genAttrs
|
||||
cfg.applets
|
||||
(a: symlink "${busybox}/bin/busybox");
|
||||
busybox = pkgs.busybox.override (attrs {
|
||||
inherit (cfg) applets options;
|
||||
});
|
||||
makeLinks = lib.attrsets.genAttrs cfg.applets (a: symlink "${busybox}/bin/busybox");
|
||||
minimalApplets = [
|
||||
# this is probably less minimal than it could be
|
||||
"arch" "ash" "base64" "basename" "bc" "brctl" "bunzip2" "bzcat" "bzip2"
|
||||
"cal" "cat" "chattr" "chgrp" "chmod" "chown" "chpst" "chroot" "clear" "cmp"
|
||||
"comm" "cp" "cpio" "cut" "date" "dhcprelay" "dd" "df" "dirname" "dmesg"
|
||||
"du" "echo" "egrep" "env" "expand" "expr" "false" "fdisk" "fgrep" "find"
|
||||
"free" "fuser" "grep" "gunzip" "gzip" "head" "hexdump" "hostname" "hwclock"
|
||||
"ifconfig" "ip" "ipaddr" "iplink" "ipneigh" "iproute" "iprule" "kill"
|
||||
"killall" "killall5" "less" "ln" "ls" "lsattr" "lsof" "md5sum" "mkdir"
|
||||
"mknod" "mktemp" "mount" "mv" "nc" "netstat" "nohup" "od" "pgrep" "pidof"
|
||||
"ping" "ping6" "pkill" "pmap" "printenv" "printf" "ps" "pwd" "readlink"
|
||||
"realpath" "reset" "rm" "rmdir" "route" "sed" "seq" "setsid" "sha1sum"
|
||||
"sha256sum" "sha512sum" "sleep" "sort" "stat" "strings" "stty" "su" "sum"
|
||||
"swapoff" "swapon" "sync" "tail" "tee" "test" "time" "touch" "tr"
|
||||
"traceroute" "traceroute6" "true" "truncate" "tty" "udhcpc" "umount"
|
||||
"uname" "unexpand" "uniq" "unlink" "unlzma" "unxz" "unzip" "uptime" "watch"
|
||||
"wc" "whoami" "xargs" "xxd" "xz" "xzcat" "yes" "zcat"
|
||||
"arch"
|
||||
"ash"
|
||||
"base64"
|
||||
"basename"
|
||||
"bc"
|
||||
"brctl"
|
||||
"bunzip2"
|
||||
"bzcat"
|
||||
"bzip2"
|
||||
"cal"
|
||||
"cat"
|
||||
"chattr"
|
||||
"chgrp"
|
||||
"chmod"
|
||||
"chown"
|
||||
"chpst"
|
||||
"chroot"
|
||||
"clear"
|
||||
"cmp"
|
||||
"comm"
|
||||
"cp"
|
||||
"cpio"
|
||||
"cut"
|
||||
"date"
|
||||
"dhcprelay"
|
||||
"dd"
|
||||
"df"
|
||||
"dirname"
|
||||
"dmesg"
|
||||
"du"
|
||||
"echo"
|
||||
"egrep"
|
||||
"env"
|
||||
"expand"
|
||||
"expr"
|
||||
"false"
|
||||
"fdisk"
|
||||
"fgrep"
|
||||
"find"
|
||||
"free"
|
||||
"fuser"
|
||||
"grep"
|
||||
"gunzip"
|
||||
"gzip"
|
||||
"head"
|
||||
"hexdump"
|
||||
"hostname"
|
||||
"hwclock"
|
||||
"ifconfig"
|
||||
"ip"
|
||||
"ipaddr"
|
||||
"iplink"
|
||||
"ipneigh"
|
||||
"iproute"
|
||||
"iprule"
|
||||
"kill"
|
||||
"killall"
|
||||
"killall5"
|
||||
"less"
|
||||
"ln"
|
||||
"ls"
|
||||
"lsattr"
|
||||
"lsof"
|
||||
"md5sum"
|
||||
"mkdir"
|
||||
"mknod"
|
||||
"mktemp"
|
||||
"mount"
|
||||
"mv"
|
||||
"nc"
|
||||
"netstat"
|
||||
"nohup"
|
||||
"od"
|
||||
"pgrep"
|
||||
"pidof"
|
||||
"ping"
|
||||
"ping6"
|
||||
"pkill"
|
||||
"pmap"
|
||||
"printenv"
|
||||
"printf"
|
||||
"ps"
|
||||
"pwd"
|
||||
"readlink"
|
||||
"realpath"
|
||||
"reset"
|
||||
"rm"
|
||||
"rmdir"
|
||||
"route"
|
||||
"sed"
|
||||
"seq"
|
||||
"setsid"
|
||||
"sha1sum"
|
||||
"sha256sum"
|
||||
"sha512sum"
|
||||
"sleep"
|
||||
"sort"
|
||||
"stat"
|
||||
"strings"
|
||||
"stty"
|
||||
"su"
|
||||
"sum"
|
||||
"swapoff"
|
||||
"swapon"
|
||||
"sync"
|
||||
"tail"
|
||||
"tee"
|
||||
"test"
|
||||
"time"
|
||||
"touch"
|
||||
"tr"
|
||||
"traceroute"
|
||||
"traceroute6"
|
||||
"true"
|
||||
"truncate"
|
||||
"tty"
|
||||
"udhcpc"
|
||||
"umount"
|
||||
"uname"
|
||||
"unexpand"
|
||||
"uniq"
|
||||
"unlink"
|
||||
"unlzma"
|
||||
"unxz"
|
||||
"unzip"
|
||||
"uptime"
|
||||
"watch"
|
||||
"wc"
|
||||
"whoami"
|
||||
"xargs"
|
||||
"xxd"
|
||||
"xz"
|
||||
"xzcat"
|
||||
"yes"
|
||||
"zcat"
|
||||
];
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
programs.busybox = {
|
||||
applets = mkOption {
|
||||
applets = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "Applets required";
|
||||
default = [];
|
||||
example = ["sh" "getty" "login"];
|
||||
default = [ ];
|
||||
example = [
|
||||
"sh"
|
||||
"getty"
|
||||
"login"
|
||||
];
|
||||
};
|
||||
options = mkOption {
|
||||
# mostly the values are y n or m, but sometimes
|
||||
# other strings are also used
|
||||
description = "Other busybox config flags that do not map directly to applet names (often prefixed FEATURE_)";
|
||||
type = types.attrsOf types.nonEmptyStr;
|
||||
default = { };
|
||||
example = { FEATURE_DD_IBS_OBS = "y"; };
|
||||
default = { };
|
||||
example = {
|
||||
FEATURE_DD_IBS_OBS = "y";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -1,10 +1,14 @@
|
||||
{
|
||||
writeFennel
|
||||
, linotify
|
||||
, anoia
|
||||
, lualinux
|
||||
writeFennel,
|
||||
linotify,
|
||||
anoia,
|
||||
lualinux,
|
||||
}:
|
||||
writeFennel "acquire-delegated-prefix" {
|
||||
packages = [ linotify anoia lualinux ];
|
||||
packages = [
|
||||
linotify
|
||||
anoia
|
||||
lualinux
|
||||
];
|
||||
mainFunction = "run";
|
||||
} ./acquire-delegated-prefix.fnl
|
||||
|
@@ -1,10 +1,14 @@
|
||||
{
|
||||
writeFennel
|
||||
, linotify
|
||||
, anoia
|
||||
, lualinux
|
||||
writeFennel,
|
||||
linotify,
|
||||
anoia,
|
||||
lualinux,
|
||||
}:
|
||||
writeFennel "acquire-wan-address" {
|
||||
packages = [ linotify anoia lualinux ];
|
||||
packages = [
|
||||
linotify
|
||||
anoia
|
||||
lualinux
|
||||
];
|
||||
mainFunction = "run";
|
||||
} ./acquire-wan-address.fnl
|
||||
|
@@ -1,14 +1,18 @@
|
||||
{
|
||||
liminix
|
||||
, callPackage
|
||||
liminix,
|
||||
callPackage,
|
||||
}:
|
||||
{ client, interface } :
|
||||
{ client, interface }:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
name = "dhcp6c.addr.${client.name}.${interface.name}";
|
||||
script = callPackage ./acquire-wan-address.nix { };
|
||||
in longrun {
|
||||
script = callPackage ./acquire-wan-address.nix { };
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
|
||||
dependencies = [ client interface ];
|
||||
dependencies = [
|
||||
client
|
||||
interface
|
||||
];
|
||||
}
|
||||
|
@@ -1,13 +1,14 @@
|
||||
{
|
||||
liminix
|
||||
, odhcp6c
|
||||
, odhcp-script
|
||||
liminix,
|
||||
odhcp6c,
|
||||
odhcp-script,
|
||||
}:
|
||||
{ interface } :
|
||||
{ interface }:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
name = "dhcp6c.${interface.name}";
|
||||
in longrun {
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
notification-fd = 10;
|
||||
run = ''
|
||||
|
@@ -9,7 +9,12 @@
|
||||
## addresses of network interfaces that you want to assign those
|
||||
## prefixes to
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
|
@@ -1,14 +1,18 @@
|
||||
{
|
||||
liminix
|
||||
, callPackage
|
||||
liminix,
|
||||
callPackage,
|
||||
}:
|
||||
{ client, interface } :
|
||||
{ client, interface }:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
name = "dhcp6c.prefix.${client.name}.${interface.name}";
|
||||
script = callPackage ./acquire-delegated-prefix.nix { };
|
||||
in longrun {
|
||||
script = callPackage ./acquire-delegated-prefix.nix { };
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
run = "${script} $SERVICE_OUTPUTS/${client.name} $(output ${interface} ifname)";
|
||||
dependencies = [ client interface ];
|
||||
dependencies = [
|
||||
client
|
||||
interface
|
||||
];
|
||||
}
|
||||
|
@@ -4,12 +4,17 @@
|
||||
## This module includes a service to provide DNS, DHCP, and IPv6
|
||||
## router advertisement for the local network.
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
system.service.dnsmasq = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
@@ -20,12 +25,12 @@ in {
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "dnsmasq";
|
||||
description = "Specifies the unix user which dnsmasq will run as" ;
|
||||
description = "Specifies the unix user which dnsmasq will run as";
|
||||
};
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "dnsmasq";
|
||||
description = "Specifies the unix group which dnsmasq will run as" ;
|
||||
description = "Specifies the unix group which dnsmasq will run as";
|
||||
};
|
||||
resolvconf = mkOption {
|
||||
type = types.nullOr liminix.lib.types.service;
|
||||
@@ -37,42 +42,47 @@ in {
|
||||
};
|
||||
upstreams = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
default = [ ];
|
||||
};
|
||||
ranges = mkOption {
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
hosts = mkOption {
|
||||
default = {};
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
mac = mkOption {
|
||||
description = ''
|
||||
MAC or other hardware address to match on. For Ethernet
|
||||
this is a 48 bit address represented as colon-separated
|
||||
hex bytes, or "id:clientid" to match a presented
|
||||
client id (IPv6 DUID)
|
||||
'';
|
||||
type = types.str;
|
||||
example = "01:20:31:4a:50";
|
||||
default = { };
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
mac = mkOption {
|
||||
description = ''
|
||||
MAC or other hardware address to match on. For Ethernet
|
||||
this is a 48 bit address represented as colon-separated
|
||||
hex bytes, or "id:clientid" to match a presented
|
||||
client id (IPv6 DUID)
|
||||
'';
|
||||
type = types.str;
|
||||
example = "01:20:31:4a:50";
|
||||
};
|
||||
v4 = mkOption {
|
||||
description = "IPv4 address to assign to this client";
|
||||
example = "192.0.2.1";
|
||||
type = types.str;
|
||||
};
|
||||
v6 = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "IPv6 addresses or interface-ids to assign to this client";
|
||||
default = [ ];
|
||||
example = [
|
||||
"fe80::42:1eff:fefd:b341"
|
||||
"::1234"
|
||||
];
|
||||
};
|
||||
leasetime = mkOption {
|
||||
type = types.int;
|
||||
default = 86400;
|
||||
};
|
||||
};
|
||||
v4 = mkOption {
|
||||
description = "IPv4 address to assign to this client";
|
||||
example = "192.0.2.1";
|
||||
type = types.str;
|
||||
};
|
||||
v6 = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "IPv6 addresses or interface-ids to assign to this client";
|
||||
default = [];
|
||||
example = [ "fe80::42:1eff:fefd:b341" "::1234"];
|
||||
};
|
||||
leasetime = mkOption {
|
||||
type = types.int;
|
||||
default = 86400;
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
domain = mkOption {
|
||||
# this can be given multiple times so probably should be
|
||||
@@ -83,13 +93,16 @@ in {
|
||||
};
|
||||
};
|
||||
users.dnsmasq = {
|
||||
uid = 51; gid= 51; gecos = "DNS/DHCP service user";
|
||||
uid = 51;
|
||||
gid = 51;
|
||||
gecos = "DNS/DHCP service user";
|
||||
dir = "/run/dnsmasq";
|
||||
shell = "/bin/false";
|
||||
};
|
||||
groups.dnsmasq = {
|
||||
gid = 51; usernames = ["dnsmasq"];
|
||||
gid = 51;
|
||||
usernames = [ "dnsmasq" ];
|
||||
};
|
||||
groups.system.usernames = ["dnsmasq"];
|
||||
groups.system.usernames = [ "dnsmasq" ];
|
||||
};
|
||||
}
|
||||
|
@@ -1,26 +1,35 @@
|
||||
{
|
||||
liminix
|
||||
, dnsmasq
|
||||
, serviceFns
|
||||
, lib
|
||||
liminix,
|
||||
dnsmasq,
|
||||
serviceFns,
|
||||
lib,
|
||||
}:
|
||||
{
|
||||
interface
|
||||
, user
|
||||
, domain
|
||||
, group
|
||||
, ranges
|
||||
, hosts
|
||||
, upstreams
|
||||
, resolvconf
|
||||
interface,
|
||||
user,
|
||||
domain,
|
||||
group,
|
||||
ranges,
|
||||
hosts,
|
||||
upstreams,
|
||||
resolvconf,
|
||||
}:
|
||||
let
|
||||
name = "${interface.name}.dnsmasq";
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) concatStrings concatStringsSep mapAttrsToList;
|
||||
hostOpt = name : { mac, v4, v6, leasetime }:
|
||||
let v6s = concatStrings (map (a : ",[${a}]") v6);
|
||||
in "--dhcp-host=${mac},${v4}${v6s},${name},${builtins.toString leasetime}";
|
||||
hostOpt =
|
||||
name:
|
||||
{
|
||||
mac,
|
||||
v4,
|
||||
v6,
|
||||
leasetime,
|
||||
}:
|
||||
let
|
||||
v6s = concatStrings (map (a: ",[${a}]") v6);
|
||||
in
|
||||
"--dhcp-host=${mac},${v4}${v6s},${name},${builtins.toString leasetime}";
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
@@ -35,7 +44,12 @@ longrun {
|
||||
${lib.concatStringsSep " " (builtins.map (r: "--server=${r}") upstreams)} \
|
||||
--keep-in-foreground \
|
||||
--dhcp-authoritative \
|
||||
${if resolvconf != null then "--resolv-file=$(output_path ${resolvconf} resolv.conf)" else "--no-resolv"} \
|
||||
${
|
||||
if resolvconf != null then
|
||||
"--resolv-file=$(output_path ${resolvconf} resolv.conf)"
|
||||
else
|
||||
"--no-resolv"
|
||||
} \
|
||||
${lib.concatStringsSep " " (mapAttrsToList hostOpt hosts)} \
|
||||
--no-hosts \
|
||||
--log-dhcp \
|
||||
@@ -44,7 +58,7 @@ longrun {
|
||||
--dhcp-leasefile=$(mkstate ${name})/leases \
|
||||
--pid-file=/run/${name}.pid
|
||||
'';
|
||||
# --log-debug \
|
||||
# --log-queries \
|
||||
# --log-debug \
|
||||
# --log-queries \
|
||||
|
||||
}
|
||||
|
@@ -1,9 +1,10 @@
|
||||
let
|
||||
drop = expr : "${expr} drop";
|
||||
accept = expr : "${expr} accept";
|
||||
drop = expr: "${expr} drop";
|
||||
accept = expr: "${expr} accept";
|
||||
mcast-scope = 8;
|
||||
allow-incoming = false;
|
||||
in {
|
||||
in
|
||||
{
|
||||
bogons-ip6 = {
|
||||
type = "filter";
|
||||
family = "ip6";
|
||||
@@ -44,7 +45,7 @@ in {
|
||||
rules = [
|
||||
(drop "ip6 saddr ::1/128") # loopback address [RFC4291]
|
||||
(drop "ip6 daddr ::1/128")
|
||||
(drop "ip6 saddr ::FFFF:0:0/96")# IPv4-mapped addresses
|
||||
(drop "ip6 saddr ::FFFF:0:0/96") # IPv4-mapped addresses
|
||||
(drop "ip6 daddr ::FFFF:0:0/96")
|
||||
(drop "ip6 saddr fe80::/10") # link-local unicast
|
||||
(drop "ip6 daddr fe80::/10")
|
||||
@@ -60,7 +61,8 @@ in {
|
||||
(drop
|
||||
# dest addr first byte 0xff, low nibble of second byte <= scope
|
||||
# https://www.mankier.com/8/nft#Payload_Expressions-Raw_Payload_Expression
|
||||
"@nh,192,8 eq 0xff @nh,204,4 le ${toString mcast-scope}")
|
||||
"@nh,192,8 eq 0xff @nh,204,4 le ${toString mcast-scope}"
|
||||
)
|
||||
|
||||
(accept "oifname @lan iifname @wan meta l4proto udp ct state established,related")
|
||||
(accept "iifname @lan oifname @wan meta l4proto udp")
|
||||
@@ -72,7 +74,7 @@ in {
|
||||
# does this ever get used or does the preceding general udp accept
|
||||
# already grab anything that might get here?
|
||||
(accept "oifname @wan udp dport 500") # IKE Protocol [RFC5996]. haha zyxel
|
||||
(accept "ip6 nexthdr 139") # Host Identity Protocol
|
||||
(accept "ip6 nexthdr 139") # Host Identity Protocol
|
||||
|
||||
## FIXME no support yet for recs 27-30 Mobility Header
|
||||
|
||||
@@ -88,9 +90,11 @@ in {
|
||||
# we can allow all reasonable inbound, or we can use an explicit
|
||||
# allowlist to enumerate the endpoints that are allowed to
|
||||
# accept inbound from the WAN
|
||||
(if allow-incoming
|
||||
then accept "oifname @lan iifname @wan"
|
||||
else "iifname @wan jump incoming-allowed-ip6"
|
||||
(
|
||||
if allow-incoming then
|
||||
accept "oifname @lan iifname @wan"
|
||||
else
|
||||
"iifname @wan jump incoming-allowed-ip6"
|
||||
)
|
||||
# allow all outbound and any inbound that's part of a
|
||||
# recognised (outbound-initiated) flow
|
||||
@@ -130,10 +134,7 @@ in {
|
||||
(accept "meta l4proto icmpv6")
|
||||
"iifname @lan jump input-ip6-lan"
|
||||
"iifname @wan jump input-ip6-wan"
|
||||
(if allow-incoming
|
||||
then accept "iifname @wan"
|
||||
else "iifname @wan jump incoming-allowed-ip6"
|
||||
)
|
||||
(if allow-incoming then accept "iifname @wan" else "iifname @wan jump incoming-allowed-ip6")
|
||||
# how does this even make sense in an input chain?
|
||||
(accept "iifname @wan ct state established,related")
|
||||
(accept "iifname @lan ")
|
||||
@@ -185,9 +186,9 @@ in {
|
||||
family = "ip";
|
||||
|
||||
rules = [
|
||||
(accept "udp dport 67") # dhcp
|
||||
(accept "udp dport 53") # dns
|
||||
(accept "tcp dport 22") # ssh
|
||||
(accept "udp dport 67") # dhcp
|
||||
(accept "udp dport 53") # dns
|
||||
(accept "tcp dport 22") # ssh
|
||||
];
|
||||
};
|
||||
|
||||
|
@@ -4,7 +4,12 @@
|
||||
## Provides a service to create an nftables ruleset based on
|
||||
## configuration supplied to it.
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
@@ -54,37 +59,44 @@ in
|
||||
};
|
||||
config = {
|
||||
system.service.firewall =
|
||||
let svc = config.system.callService ./service.nix {
|
||||
extraRules = mkOption {
|
||||
type = types.attrsOf types.attrs;
|
||||
description = "firewall ruleset";
|
||||
default = {};
|
||||
};
|
||||
zones = mkOption {
|
||||
type = types.attrsOf (types.listOf liminix.lib.types.service);
|
||||
default = {};
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
lan = with config.hardware.networkInterfaces; [ int ];
|
||||
wan = [ config.services.ppp0 ];
|
||||
}
|
||||
'';
|
||||
};
|
||||
rules = mkOption {
|
||||
type = types.attrsOf types.attrs; # we could usefully tighten this a bit :-)
|
||||
default = import ./default-rules.nix;
|
||||
description = "firewall ruleset";
|
||||
};
|
||||
let
|
||||
svc = config.system.callService ./service.nix {
|
||||
extraRules = mkOption {
|
||||
type = types.attrsOf types.attrs;
|
||||
description = "firewall ruleset";
|
||||
default = { };
|
||||
};
|
||||
in svc // {
|
||||
build = args :
|
||||
let args' = args // {
|
||||
dependencies = (args.dependencies or []) ++ [kmodules];
|
||||
};
|
||||
in svc.build args' ;
|
||||
zones = mkOption {
|
||||
type = types.attrsOf (types.listOf liminix.lib.types.service);
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
lan = with config.hardware.networkInterfaces; [ int ];
|
||||
wan = [ config.services.ppp0 ];
|
||||
}
|
||||
'';
|
||||
};
|
||||
rules = mkOption {
|
||||
type = types.attrsOf types.attrs; # we could usefully tighten this a bit :-)
|
||||
default = import ./default-rules.nix;
|
||||
description = "firewall ruleset";
|
||||
};
|
||||
};
|
||||
in
|
||||
svc
|
||||
// {
|
||||
build =
|
||||
args:
|
||||
let
|
||||
args' = args // {
|
||||
dependencies = (args.dependencies or [ ]) ++ [ kmodules ];
|
||||
};
|
||||
in
|
||||
svc.build args';
|
||||
};
|
||||
programs.busybox.applets = [
|
||||
"insmod" "rmmod"
|
||||
"insmod"
|
||||
"rmmod"
|
||||
];
|
||||
kernel.config = {
|
||||
NETFILTER = "y";
|
||||
@@ -94,7 +106,7 @@ in
|
||||
|
||||
NETLINK_DIAG = "y";
|
||||
|
||||
IP6_NF_IPTABLES= "m";
|
||||
IP6_NF_IPTABLES = "m";
|
||||
IP_NF_IPTABLES = "m";
|
||||
IP_NF_NAT = "m";
|
||||
IP_NF_TARGET_MASQUERADE = "m";
|
||||
|
@@ -1,37 +1,44 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, firewallgen
|
||||
, nftables
|
||||
, writeFennel
|
||||
, anoia
|
||||
, lualinux
|
||||
, linotify
|
||||
liminix,
|
||||
lib,
|
||||
firewallgen,
|
||||
nftables,
|
||||
writeFennel,
|
||||
anoia,
|
||||
lualinux,
|
||||
linotify,
|
||||
}:
|
||||
{
|
||||
rules,
|
||||
extraRules,
|
||||
zones,
|
||||
}:
|
||||
{ rules, extraRules, zones }:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib.attrsets) mapAttrs' nameValuePair mapAttrsToList;
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
inherit (lib.lists) flatten;
|
||||
mkSet = family : name :
|
||||
nameValuePair
|
||||
"${name}-set-${family}"
|
||||
{
|
||||
kind = "set";
|
||||
inherit name family;
|
||||
type = "ifname";
|
||||
};
|
||||
sets = (mapAttrs' (n : _ : mkSet "ip" n) zones) //
|
||||
(mapAttrs' (n : _ : mkSet "ip6" n) zones);
|
||||
mkSet =
|
||||
family: name:
|
||||
nameValuePair "${name}-set-${family}" {
|
||||
kind = "set";
|
||||
inherit name family;
|
||||
type = "ifname";
|
||||
};
|
||||
sets = (mapAttrs' (n: _: mkSet "ip" n) zones) // (mapAttrs' (n: _: mkSet "ip6" n) zones);
|
||||
allRules = lib.recursiveUpdate extraRules (lib.recursiveUpdate (builtins.trace sets sets) rules);
|
||||
script = firewallgen "firewall1.nft" allRules;
|
||||
ifwatch = writeFennel "ifwatch" {
|
||||
packages = [anoia lualinux linotify];
|
||||
packages = [
|
||||
anoia
|
||||
lualinux
|
||||
linotify
|
||||
];
|
||||
mainFunction = "run";
|
||||
} ./ifwatch.fnl ;
|
||||
watchArg = z : intfs : map (i: "${z}:${i}/.outputs") intfs;
|
||||
in longrun {
|
||||
} ./ifwatch.fnl;
|
||||
watchArg = z: intfs: map (i: "${z}:${i}/.outputs") intfs;
|
||||
in
|
||||
longrun {
|
||||
name = "firewall";
|
||||
run = ''
|
||||
${script}
|
||||
|
@@ -75,17 +75,27 @@ in
|
||||
type = types.ints.unsigned;
|
||||
};
|
||||
};
|
||||
loadAddress = mkOption { type = types.ints.unsigned; default = null; };
|
||||
loadAddress = mkOption {
|
||||
type = types.ints.unsigned;
|
||||
default = null;
|
||||
};
|
||||
entryPoint = mkOption { type = types.ints.unsigned; };
|
||||
alignment = mkOption { type = types.nullOr types.ints.unsigned; default = null; description = "Alignment passed to `mkimage` for FIT"; };
|
||||
alignment = mkOption {
|
||||
type = types.nullOr types.ints.unsigned;
|
||||
default = null;
|
||||
description = "Alignment passed to `mkimage` for FIT";
|
||||
};
|
||||
radios = mkOption {
|
||||
description = ''
|
||||
Kernel modules (from mac80211 package) required for the
|
||||
wireless devices on this board
|
||||
'';
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = ["ath9k" "ath10k"];
|
||||
default = [ ];
|
||||
example = [
|
||||
"ath9k"
|
||||
"ath10k"
|
||||
];
|
||||
};
|
||||
rootDevice = mkOption {
|
||||
description = "Full path to preferred root device";
|
||||
|
@@ -6,13 +6,18 @@
|
||||
## have other behaviours by e.g. combining this service with a round-robin
|
||||
## for failover)
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
in
|
||||
# inherit (pkgs.liminix.services) longrun;
|
||||
in {
|
||||
{
|
||||
options = {
|
||||
system.service.health-check = mkOption {
|
||||
description = "run a service while periodically checking it is healthy";
|
||||
@@ -23,13 +28,13 @@ in {
|
||||
service = mkOption {
|
||||
type = liminix.lib.types.service;
|
||||
};
|
||||
interval = mkOption {
|
||||
interval = mkOption {
|
||||
description = "interval between checks, in seconds";
|
||||
type = types.int;
|
||||
default = 10;
|
||||
example = 10;
|
||||
};
|
||||
threshold = mkOption {
|
||||
threshold = mkOption {
|
||||
description = "number of consecutive failures required for the service to be kicked";
|
||||
type = types.int;
|
||||
example = 3;
|
||||
@@ -39,5 +44,5 @@ in {
|
||||
type = types.path;
|
||||
};
|
||||
};
|
||||
config.programs.busybox.applets = ["expr"];
|
||||
config.programs.busybox.applets = [ "expr" ];
|
||||
}
|
||||
|
@@ -1,37 +1,50 @@
|
||||
{
|
||||
liminix, lib, lim, s6
|
||||
liminix,
|
||||
lib,
|
||||
lim,
|
||||
s6,
|
||||
}:
|
||||
{
|
||||
service,
|
||||
interval,
|
||||
threshold,
|
||||
healthCheck,
|
||||
}:
|
||||
{ service, interval, threshold, healthCheck } :
|
||||
let
|
||||
inherit (liminix.services) oneshot longrun;
|
||||
inherit (builtins) toString;
|
||||
inherit (service) name;
|
||||
checker = let name' = "check-${name}"; in longrun {
|
||||
name = name';
|
||||
run = ''
|
||||
fails=0
|
||||
echo waiting for /run/service/${name}
|
||||
${s6}/bin/s6-svwait -U /run/service/${name} || exit
|
||||
while sleep ${toString interval} ; do
|
||||
${healthCheck}
|
||||
if test $? -gt 0; then
|
||||
fails=$(expr $fails + 1)
|
||||
else
|
||||
fails=0
|
||||
fi
|
||||
echo fails $fails/${toString threshold} for ${name}
|
||||
if test "$fails" -gt "${toString threshold}" ; then
|
||||
echo time to die
|
||||
${s6}/bin/s6-svc -r /run/service/${name}
|
||||
echo bounced
|
||||
fails=0
|
||||
echo waiting for /run/service/${name}
|
||||
${s6}/bin/s6-svwait -U /run/service/${name}
|
||||
fi
|
||||
done
|
||||
'';
|
||||
};
|
||||
in service.overrideAttrs(o: {
|
||||
buildInputs = (lim.orEmpty o.buildInputs) ++ [ checker ];
|
||||
checker =
|
||||
let
|
||||
name' = "check-${name}";
|
||||
in
|
||||
longrun {
|
||||
name = name';
|
||||
run = ''
|
||||
fails=0
|
||||
echo waiting for /run/service/${name}
|
||||
${s6}/bin/s6-svwait -U /run/service/${name} || exit
|
||||
while sleep ${toString interval} ; do
|
||||
${healthCheck}
|
||||
if test $? -gt 0; then
|
||||
fails=$(expr $fails + 1)
|
||||
else
|
||||
fails=0
|
||||
fi
|
||||
echo fails $fails/${toString threshold} for ${name}
|
||||
if test "$fails" -gt "${toString threshold}" ; then
|
||||
echo time to die
|
||||
${s6}/bin/s6-svc -r /run/service/${name}
|
||||
echo bounced
|
||||
fails=0
|
||||
echo waiting for /run/service/${name}
|
||||
${s6}/bin/s6-svwait -U /run/service/${name}
|
||||
fi
|
||||
done
|
||||
'';
|
||||
};
|
||||
in
|
||||
service.overrideAttrs (o: {
|
||||
buildInputs = (lim.orEmpty o.buildInputs) ++ [ checker ];
|
||||
dependencies = (lim.orEmpty o.dependencies) ++ [ checker ];
|
||||
})
|
||||
|
@@ -11,11 +11,17 @@
|
||||
## If you have more than one wireless network interface (e.g.
|
||||
## wlan0, wlan1) you can run an instance of hostapd on each of them.
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
in {
|
||||
in
|
||||
{
|
||||
imports = [ ../secrets ];
|
||||
options = {
|
||||
system.service.hostapd = mkOption {
|
||||
|
@@ -1,16 +1,23 @@
|
||||
{
|
||||
liminix
|
||||
, svc
|
||||
, hostapd
|
||||
, output-template
|
||||
, writeText
|
||||
, lib
|
||||
liminix,
|
||||
svc,
|
||||
hostapd,
|
||||
output-template,
|
||||
writeText,
|
||||
lib,
|
||||
}:
|
||||
{ interface, params} :
|
||||
{ interface, params }:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) concatStringsSep mapAttrsToList unique ;
|
||||
inherit (builtins) map filter attrValues length head typeOf;
|
||||
inherit (lib) concatStringsSep mapAttrsToList unique;
|
||||
inherit (builtins)
|
||||
map
|
||||
filter
|
||||
attrValues
|
||||
length
|
||||
head
|
||||
typeOf
|
||||
;
|
||||
|
||||
# This is not a friendly interface to configuring a wireless AP: it
|
||||
# just passes everything straight through to the hostapd config.
|
||||
@@ -19,27 +26,31 @@ let
|
||||
# extraParams
|
||||
|
||||
name = "${interface.name}.hostapd";
|
||||
defaults = {
|
||||
defaults = {
|
||||
driver = "nl80211";
|
||||
logger_syslog = "-1";
|
||||
logger_syslog_level = 1;
|
||||
ctrl_interface = "/run/${name}";
|
||||
ctrl_interface_group = 0;
|
||||
};
|
||||
attrs = defaults // params ;
|
||||
literal_or_output = o: ({
|
||||
string = builtins.toJSON;
|
||||
int = builtins.toJSON;
|
||||
lambda = (o: "output(${builtins.toJSON (o "service")}, ${builtins.toJSON (o "path")})");
|
||||
}.${builtins.typeOf o}) o;
|
||||
attrs = defaults // params;
|
||||
literal_or_output =
|
||||
o:
|
||||
(
|
||||
{
|
||||
string = builtins.toJSON;
|
||||
int = builtins.toJSON;
|
||||
lambda = (o: "output(${builtins.toJSON (o "service")}, ${builtins.toJSON (o "path")})");
|
||||
}
|
||||
.${builtins.typeOf o}
|
||||
)
|
||||
o;
|
||||
|
||||
conf =
|
||||
(writeText "hostapd.conf.in"
|
||||
((concatStringsSep
|
||||
"\n"
|
||||
(mapAttrsToList
|
||||
(n : v : "${n}={{ ${literal_or_output v} }}")
|
||||
attrs)) + "\n"));
|
||||
conf = (
|
||||
writeText "hostapd.conf.in" (
|
||||
(concatStringsSep "\n" (mapAttrsToList (n: v: "${n}={{ ${literal_or_output v} }}") attrs)) + "\n"
|
||||
)
|
||||
);
|
||||
service = longrun {
|
||||
inherit name;
|
||||
dependencies = [ interface ];
|
||||
@@ -51,7 +62,8 @@ let
|
||||
'';
|
||||
};
|
||||
watch = filter (f: typeOf f == "lambda") (attrValues attrs);
|
||||
in svc.secrets.subscriber.build {
|
||||
in
|
||||
svc.secrets.subscriber.build {
|
||||
inherit service watch;
|
||||
action = "restart-all";
|
||||
}
|
||||
|
@@ -1,8 +1,14 @@
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
hostname = mkOption {
|
||||
description = ''
|
||||
|
@@ -1,10 +1,15 @@
|
||||
{ config, pkgs, lib, ... } :
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (pkgs) liminix;
|
||||
inherit (lib) mkOption types;
|
||||
in {
|
||||
options.system.service.ifwait =
|
||||
mkOption { type = liminix.lib.types.serviceDefn; };
|
||||
in
|
||||
{
|
||||
options.system.service.ifwait = mkOption { type = liminix.lib.types.serviceDefn; };
|
||||
|
||||
config.system.service.ifwait = config.system.callService ./ifwait.nix {
|
||||
state = mkOption { type = types.str; };
|
||||
|
@@ -1,12 +1,13 @@
|
||||
{ ifwait, liminix } :
|
||||
{ ifwait, liminix }:
|
||||
{
|
||||
state
|
||||
, interface
|
||||
, service
|
||||
state,
|
||||
interface,
|
||||
service,
|
||||
}:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
in longrun {
|
||||
in
|
||||
longrun {
|
||||
name = "ifwait.${interface.name}";
|
||||
buildInputs = [ service ];
|
||||
restart-on-upgrade = true;
|
||||
|
@@ -3,26 +3,36 @@
|
||||
##
|
||||
##
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types ;
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix openwrt;
|
||||
|
||||
mergeConditionals = conf : conditions :
|
||||
mergeConditionals =
|
||||
conf: conditions:
|
||||
# for each key in conditions, if it is present in conf
|
||||
# then merge the associated value into conf
|
||||
lib.foldlAttrs
|
||||
(acc: name: value:
|
||||
if (conf ? ${name}) && (conf.${name} != "n")
|
||||
then acc // value
|
||||
else acc)
|
||||
conf
|
||||
conditions;
|
||||
in {
|
||||
lib.foldlAttrs (
|
||||
acc: name: value:
|
||||
if (conf ? ${name}) && (conf.${name} != "n") then acc // value else acc
|
||||
) conf conditions;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
kernel = {
|
||||
src = mkOption { type = types.path; default = openwrt.kernelSrc; } ;
|
||||
version = mkOption { type = types.str; default = openwrt.kernelVersion;} ;
|
||||
src = mkOption {
|
||||
type = types.path;
|
||||
default = openwrt.kernelSrc;
|
||||
};
|
||||
version = mkOption {
|
||||
type = types.str;
|
||||
default = openwrt.kernelVersion;
|
||||
};
|
||||
modular = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
@@ -54,7 +64,7 @@ in {
|
||||
some other option is present.
|
||||
'';
|
||||
type = types.attrsOf (types.attrsOf types.nonEmptyStr);
|
||||
default = {};
|
||||
default = { };
|
||||
example = {
|
||||
USB = {
|
||||
USB_XHCI_MVEBU = "y";
|
||||
@@ -70,10 +80,9 @@ in {
|
||||
config = {
|
||||
system.outputs.kernel =
|
||||
let
|
||||
mergedConfig = mergeConditionals
|
||||
config.kernel.config
|
||||
config.kernel.conditionalConfig;
|
||||
in liminix.builders.kernel.override {
|
||||
mergedConfig = mergeConditionals config.kernel.config config.kernel.conditionalConfig;
|
||||
in
|
||||
liminix.builders.kernel.override {
|
||||
config = mergedConfig;
|
||||
inherit (config.kernel) version src extraPatchPhase;
|
||||
targets = config.kernel.makeTargets;
|
||||
@@ -81,7 +90,7 @@ in {
|
||||
|
||||
kernel = rec {
|
||||
modular = true; # disabling this is not yet supported
|
||||
makeTargets = ["vmlinux"];
|
||||
makeTargets = [ "vmlinux" ];
|
||||
config = {
|
||||
IKCONFIG = "y";
|
||||
IKCONFIG_PROC = "y";
|
||||
@@ -96,10 +105,10 @@ in {
|
||||
UNIX = "y";
|
||||
INET = "y";
|
||||
IPV6 = "y";
|
||||
PACKET = "y"; # for ppp, tcpdump ...
|
||||
SYSVIPC= "y";
|
||||
PACKET = "y"; # for ppp, tcpdump ...
|
||||
SYSVIPC = "y";
|
||||
|
||||
NETDEVICES = "y"; # even PPP needs this
|
||||
NETDEVICES = "y"; # even PPP needs this
|
||||
|
||||
# disabling this option causes the kernel to use an "empty"
|
||||
# initramfs instead: it has a /dev/console node and not much
|
||||
|
@@ -1,7 +1,13 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (pkgs.liminix.services) longrun;
|
||||
in {
|
||||
in
|
||||
{
|
||||
config.services.klogd = longrun {
|
||||
name = "klogd";
|
||||
run = ''
|
||||
|
@@ -1,7 +1,13 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkOption types;
|
||||
in {
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkEnableOption
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
logging = {
|
||||
persistent = {
|
||||
@@ -9,11 +15,11 @@ in {
|
||||
};
|
||||
};
|
||||
};
|
||||
config = {
|
||||
kernel.config = mkIf config.logging.persistent.enable {
|
||||
PSTORE = "y";
|
||||
PSTORE_PMSG = "y";
|
||||
PSTORE_RAM = "y";
|
||||
};
|
||||
};
|
||||
config = {
|
||||
kernel.config = mkIf config.logging.persistent.enable {
|
||||
PSTORE = "y";
|
||||
PSTORE_PMSG = "y";
|
||||
PSTORE_RAM = "y";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
{ config, pkgs, ...} :
|
||||
let inherit (pkgs.liminix.services) oneshot longrun;
|
||||
in {
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
inherit (pkgs.liminix.services) oneshot longrun;
|
||||
in
|
||||
{
|
||||
config = {
|
||||
services = rec {
|
||||
mdevd = longrun {
|
||||
|
@@ -2,53 +2,74 @@
|
||||
##
|
||||
## Mount filesystems
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
system.service.mount = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
};
|
||||
imports = [ ../mdevd.nix ../uevent-rule ];
|
||||
imports = [
|
||||
../mdevd.nix
|
||||
../uevent-rule
|
||||
];
|
||||
config.system.service.mount =
|
||||
let svc = config.system.callService ./service.nix {
|
||||
partlabel = mkOption {
|
||||
type = types.str;
|
||||
example = "my-usb-stick";
|
||||
};
|
||||
mountpoint = mkOption {
|
||||
type = types.str;
|
||||
example = "/mnt/media";
|
||||
};
|
||||
options = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
example = ["noatime" "ro" "sync"];
|
||||
};
|
||||
fstype = mkOption {
|
||||
type = types.str;
|
||||
default = "auto";
|
||||
example = "vfat";
|
||||
};
|
||||
let
|
||||
svc = config.system.callService ./service.nix {
|
||||
partlabel = mkOption {
|
||||
type = types.str;
|
||||
example = "my-usb-stick";
|
||||
};
|
||||
in svc // {
|
||||
build = args:
|
||||
let args' = args // {
|
||||
dependencies = (args.dependencies or []) ++ [
|
||||
config.services.mdevd
|
||||
config.services.devout
|
||||
];
|
||||
};
|
||||
in svc.build args' ;
|
||||
mountpoint = mkOption {
|
||||
type = types.str;
|
||||
example = "/mnt/media";
|
||||
};
|
||||
options = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"noatime"
|
||||
"ro"
|
||||
"sync"
|
||||
];
|
||||
};
|
||||
fstype = mkOption {
|
||||
type = types.str;
|
||||
default = "auto";
|
||||
example = "vfat";
|
||||
};
|
||||
};
|
||||
in
|
||||
svc
|
||||
// {
|
||||
build =
|
||||
args:
|
||||
let
|
||||
args' = args // {
|
||||
dependencies = (args.dependencies or [ ]) ++ [
|
||||
config.services.mdevd
|
||||
config.services.devout
|
||||
];
|
||||
};
|
||||
in
|
||||
svc.build args';
|
||||
};
|
||||
|
||||
config.programs.busybox = {
|
||||
applets = ["blkid" "findfs"];
|
||||
config.programs.busybox = {
|
||||
applets = [
|
||||
"blkid"
|
||||
"findfs"
|
||||
];
|
||||
options = {
|
||||
FEATURE_BLKID_TYPE = "y";
|
||||
FEATURE_MOUNT_FLAGS = "y";
|
||||
|
@@ -1,15 +1,19 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, svc
|
||||
liminix,
|
||||
lib,
|
||||
svc,
|
||||
}:
|
||||
{
|
||||
partlabel,
|
||||
mountpoint,
|
||||
options,
|
||||
fstype,
|
||||
}:
|
||||
{ partlabel, mountpoint, options, fstype }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
device = "/dev/disk/by-partlabel/${partlabel}";
|
||||
name = "mount.${lib.strings.sanitizeDerivationName (lib.escapeURL mountpoint)}";
|
||||
options_string =
|
||||
if options == [] then "" else "-o ${lib.concatStringsSep "," options}";
|
||||
options_string = if options == [ ] then "" else "-o ${lib.concatStringsSep "," options}";
|
||||
controller = svc.uevent-rule.build {
|
||||
serviceName = name;
|
||||
symlink = device;
|
||||
@@ -18,7 +22,8 @@ let
|
||||
devtype = "partition";
|
||||
};
|
||||
};
|
||||
in oneshot {
|
||||
in
|
||||
oneshot {
|
||||
inherit name;
|
||||
timeout-up = 3600;
|
||||
up = "mount -t ${fstype} ${options_string} ${device} ${mountpoint}";
|
||||
|
@@ -1,9 +1,14 @@
|
||||
{
|
||||
liminix
|
||||
, serviceFns
|
||||
, lib
|
||||
liminix,
|
||||
serviceFns,
|
||||
lib,
|
||||
}:
|
||||
{
|
||||
interface,
|
||||
family,
|
||||
address,
|
||||
prefixLength,
|
||||
}:
|
||||
{interface, family, address, prefixLength} :
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
# rather depending on the assumption that nobody will
|
||||
@@ -20,8 +25,9 @@ let
|
||||
echo $dev > ifname
|
||||
)
|
||||
'';
|
||||
in oneshot {
|
||||
in
|
||||
oneshot {
|
||||
inherit name up;
|
||||
down = "true"; # this has been broken for ~ ages
|
||||
down = "true"; # this has been broken for ~ ages
|
||||
dependencies = [ interface ];
|
||||
}
|
||||
|
@@ -4,13 +4,18 @@
|
||||
## Basic network services for creating hardware ethernet devices
|
||||
## and adding addresses
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
inherit (pkgs.liminix.services) bundle;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
system.service.network = {
|
||||
link = mkOption {
|
||||
@@ -42,17 +47,18 @@ in {
|
||||
lo =
|
||||
let
|
||||
net = config.system.service.network;
|
||||
iface = net.link.build { ifname = "lo";};
|
||||
in bundle {
|
||||
iface = net.link.build { ifname = "lo"; };
|
||||
in
|
||||
bundle {
|
||||
name = "loopback";
|
||||
contents = [
|
||||
( net.address.build {
|
||||
(net.address.build {
|
||||
interface = iface;
|
||||
family = "inet";
|
||||
address ="127.0.0.1";
|
||||
address = "127.0.0.1";
|
||||
prefixLength = 8;
|
||||
})
|
||||
( net.address.build {
|
||||
(net.address.build {
|
||||
interface = iface;
|
||||
family = "inet6";
|
||||
address = "::1";
|
||||
@@ -82,7 +88,8 @@ in {
|
||||
Path to the sysfs node of the device. If you provide this
|
||||
and the ifname option, the device will be renamed to the
|
||||
name given by ifname.
|
||||
''; };
|
||||
'';
|
||||
};
|
||||
# other "ip link add" options could go here as well
|
||||
mtu = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
@@ -94,7 +101,10 @@ in {
|
||||
type = liminix.lib.types.service;
|
||||
};
|
||||
family = mkOption {
|
||||
type = types.enum [ "inet" "inet6" ];
|
||||
type = types.enum [
|
||||
"inet"
|
||||
"inet6"
|
||||
];
|
||||
};
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
|
@@ -1,14 +1,14 @@
|
||||
{
|
||||
liminix
|
||||
, writeAshScript
|
||||
, serviceFns
|
||||
, lib
|
||||
} :
|
||||
liminix,
|
||||
writeAshScript,
|
||||
serviceFns,
|
||||
lib,
|
||||
}:
|
||||
{ interface }:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
name = "${interface.name}.dhcpc";
|
||||
script = writeAshScript "dhcp-notify" { } ''
|
||||
script = writeAshScript "dhcp-notify" { } ''
|
||||
. ${serviceFns}
|
||||
exec 2>&1
|
||||
action=$1
|
||||
@@ -38,7 +38,8 @@ let
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
in longrun {
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
run = "exec /bin/udhcpc -f -i $(output ${interface} ifname) -x hostname:$(cat /proc/sys/kernel/hostname) -s ${script}";
|
||||
notification-fd = 10;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
liminix,
|
||||
lib,
|
||||
}:
|
||||
{ enableIPv4, enableIPv6 }:
|
||||
let
|
||||
@@ -8,11 +8,9 @@ let
|
||||
ip4 = "/proc/sys/net/ipv4/conf/all/forwarding";
|
||||
ip6 = "/proc/sys/net/ipv6/conf/all/forwarding";
|
||||
opt = lib.optionalString;
|
||||
sysctls = b :
|
||||
""
|
||||
+ opt enableIPv4 "echo ${b} > ${ip4}\n"
|
||||
+ opt enableIPv6 "echo ${b} > ${ip6}\n";
|
||||
in oneshot {
|
||||
sysctls = b: "" + opt enableIPv4 "echo ${b} > ${ip4}\n" + opt enableIPv6 "echo ${b} > ${ip6}\n";
|
||||
in
|
||||
oneshot {
|
||||
name = "forwarding${opt enableIPv4 "4"}${opt enableIPv6 "6"}";
|
||||
up = sysctls "1";
|
||||
down = sysctls "0";
|
||||
|
@@ -1,23 +1,27 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
liminix,
|
||||
lib,
|
||||
}:
|
||||
{
|
||||
ifname
|
||||
, devpath ? null
|
||||
, mtu} :
|
||||
ifname,
|
||||
devpath ? null,
|
||||
mtu,
|
||||
}:
|
||||
# if devpath is supplied, we rename the interface at that
|
||||
# path to have the specified name.
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
name = "${ifname}.link";
|
||||
rename = if devpath != null
|
||||
then ''
|
||||
oldname=$(cd /sys${devpath} && cd net/ && echo *)
|
||||
ip link set ''${oldname} name ${ifname}
|
||||
''
|
||||
else "";
|
||||
in oneshot {
|
||||
rename =
|
||||
if devpath != null then
|
||||
''
|
||||
oldname=$(cd /sys${devpath} && cd net/ && echo *)
|
||||
ip link set ''${oldname} name ${ifname}
|
||||
''
|
||||
else
|
||||
"";
|
||||
in
|
||||
oneshot {
|
||||
inherit name;
|
||||
up = ''
|
||||
${rename}
|
||||
|
@@ -1,20 +1,30 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
liminix,
|
||||
lib,
|
||||
}:
|
||||
{
|
||||
target,
|
||||
via,
|
||||
interface ? null,
|
||||
metric,
|
||||
}:
|
||||
{ target, via, interface ? null, metric }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
with_dev = if interface != null then "dev $(output ${interface} ifname)" else "";
|
||||
target_hash = builtins.substring 0 12 (builtins.hashString "sha256" target);
|
||||
via_hash = builtins.substring 0 12 (builtins.hashString "sha256" via);
|
||||
in oneshot {
|
||||
name = "route-${target_hash}-${builtins.substring 0 12 (builtins.hashString "sha256" "${via_hash}-${if interface!=null then interface.name else ""}")}";
|
||||
in
|
||||
oneshot {
|
||||
name = "route-${target_hash}-${
|
||||
builtins.substring 0 12 (
|
||||
builtins.hashString "sha256" "${via_hash}-${if interface != null then interface.name else ""}"
|
||||
)
|
||||
}";
|
||||
up = ''
|
||||
ip route add ${target} via ${via} metric ${toString metric} ${with_dev}
|
||||
'';
|
||||
down = ''
|
||||
ip route del ${target} via ${via} ${with_dev}
|
||||
'';
|
||||
dependencies = [] ++ lib.optional (interface != null) interface;
|
||||
dependencies = [ ] ++ lib.optional (interface != null) interface;
|
||||
}
|
||||
|
@@ -6,12 +6,18 @@
|
||||
## optionally also provide time service to its peers. The
|
||||
## implementation used in Liminix is Chrony
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
serverOpts = types.listOf types.str;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
system.service.ntp = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
@@ -23,23 +29,36 @@ in {
|
||||
type = types.str;
|
||||
default = "ntp";
|
||||
};
|
||||
servers = mkOption { type = types.attrsOf serverOpts; default = {}; };
|
||||
pools = mkOption { type = types.attrsOf serverOpts; default = {}; };
|
||||
peers = mkOption { type = types.attrsOf serverOpts; default = {}; };
|
||||
servers = mkOption {
|
||||
type = types.attrsOf serverOpts;
|
||||
default = { };
|
||||
};
|
||||
pools = mkOption {
|
||||
type = types.attrsOf serverOpts;
|
||||
default = { };
|
||||
};
|
||||
peers = mkOption {
|
||||
type = types.attrsOf serverOpts;
|
||||
default = { };
|
||||
};
|
||||
makestep = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr
|
||||
(types.submodule {
|
||||
type = types.nullOr (
|
||||
types.submodule {
|
||||
options = {
|
||||
threshold = mkOption { type = types.number; default = null;};
|
||||
threshold = mkOption {
|
||||
type = types.number;
|
||||
default = null;
|
||||
};
|
||||
limit = mkOption { type = types.number; };
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
allow = mkOption {
|
||||
description = "subnets from which NTP clients are allowed to access the server";
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
default = [ ];
|
||||
};
|
||||
bindaddress = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
@@ -60,7 +79,9 @@ in {
|
||||
};
|
||||
};
|
||||
users.ntp = {
|
||||
uid = 52; gid= 52; gecos = "Unprivileged NTP user";
|
||||
uid = 52;
|
||||
gid = 52;
|
||||
gecos = "Unprivileged NTP user";
|
||||
dir = "/run/ntp";
|
||||
shell = "/bin/false";
|
||||
};
|
||||
|
@@ -1,25 +1,23 @@
|
||||
{
|
||||
liminix
|
||||
, chrony
|
||||
, lib
|
||||
, writeText
|
||||
liminix,
|
||||
chrony,
|
||||
lib,
|
||||
writeText,
|
||||
}:
|
||||
params:
|
||||
let
|
||||
name = "ntp"; # bad name, needs to be unique
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) concatStringsSep mapAttrsToList;
|
||||
configFile = p:
|
||||
(mapAttrsToList (name: opts: "server ${name} ${concatStringsSep "" opts}")
|
||||
p.servers)
|
||||
++
|
||||
(mapAttrsToList (name: opts: "pool ${name} ${concatStringsSep "" opts}")
|
||||
p.pools)
|
||||
++
|
||||
(mapAttrsToList (name: opts: "peer ${name} ${concatStringsSep "" opts}")
|
||||
p.peers)
|
||||
configFile =
|
||||
p:
|
||||
(mapAttrsToList (name: opts: "server ${name} ${concatStringsSep "" opts}") p.servers)
|
||||
++ (mapAttrsToList (name: opts: "pool ${name} ${concatStringsSep "" opts}") p.pools)
|
||||
++ (mapAttrsToList (name: opts: "peer ${name} ${concatStringsSep "" opts}") p.peers)
|
||||
++ lib.optional (p.user != null) "user ${p.user}"
|
||||
++ (lib.optional (p.makestep != null) "makestep ${toString p.makestep.threshold} ${toString p.makestep.limit}")
|
||||
++ (lib.optional (
|
||||
p.makestep != null
|
||||
) "makestep ${toString p.makestep.threshold} ${toString p.makestep.limit}")
|
||||
++ (map (n: "allow ${n}") p.allow)
|
||||
++ (lib.optional (p.bindaddress != null) "bindaddress ${p.bindaddress}")
|
||||
++ (lib.optional (p.binddevice != null) "binddevice ${p.binddevice}")
|
||||
@@ -28,11 +26,11 @@ let
|
||||
"bindcmdaddress /" # disable unix socket
|
||||
"pidfile /run/${name}.pid"
|
||||
]
|
||||
++ [p.extraConfig];
|
||||
++ [ p.extraConfig ];
|
||||
|
||||
config = writeText "chrony.conf"
|
||||
(concatStringsSep "\n" (configFile params));
|
||||
in longrun {
|
||||
config = writeText "chrony.conf" (concatStringsSep "\n" (configFile params));
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
run = "${chrony}/bin/chronyd -f ${config} -d";
|
||||
}
|
||||
|
@@ -97,7 +97,7 @@ in
|
||||
system.outputs = rec {
|
||||
dtb = liminix.builders.dtb {
|
||||
inherit (config.boot) commandLine;
|
||||
dts = [config.hardware.dts.src] ++ config.hardware.dts.includes;
|
||||
dts = [ config.hardware.dts.src ] ++ config.hardware.dts.includes;
|
||||
includes = config.hardware.dts.includePaths ++ [
|
||||
"${o.kernel.headers}/include"
|
||||
];
|
||||
@@ -105,7 +105,8 @@ in
|
||||
rootdir =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
in runCommand "mktree" { } ''
|
||||
in
|
||||
runCommand "mktree" { } ''
|
||||
mkdir -p $out/nix/store/ $out/secrets $out/boot
|
||||
cp ${o.systemConfiguration}/bin/activate $out/activate
|
||||
ln -s ${pkgs.s6-init-bin}/bin/init $out/init
|
||||
@@ -115,14 +116,18 @@ in
|
||||
done
|
||||
'';
|
||||
bootablerootdir =
|
||||
let inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
in runCommand "add-slash-boot" { } ''
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
in
|
||||
runCommand "add-slash-boot" { } ''
|
||||
cp -a ${o.rootdir} $out
|
||||
${if o.bootfiles != null
|
||||
then "(cd $out && chmod -R +w . && rmdir boot && cp -a ${o.bootfiles} boot)"
|
||||
else ""
|
||||
}
|
||||
'';
|
||||
${
|
||||
if o.bootfiles != null then
|
||||
"(cd $out && chmod -R +w . && rmdir boot && cp -a ${o.bootfiles} boot)"
|
||||
else
|
||||
""
|
||||
}
|
||||
'';
|
||||
manifest = writeText "manifest.json" (builtins.toJSON config.filesystem.contents);
|
||||
};
|
||||
};
|
||||
|
@@ -1,21 +1,28 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkEnableOption
|
||||
mkOption
|
||||
types
|
||||
concatStringsSep
|
||||
;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
cfg = config.boot.loader.extlinux;
|
||||
o = config.system.outputs;
|
||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||
wantsDtb = config.hardware.dts ? src && config.hardware.dts.src != null;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options.boot.loader.extlinux.enable = mkEnableOption "extlinux";
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
system.outputs.bootfiles = pkgs.runCommand "extlinux" {} ''
|
||||
system.outputs.bootfiles = pkgs.runCommand "extlinux" { } ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
${if wantsDtb then "cp ${o.dtb} dtb" else "true"}
|
||||
|
@@ -1,21 +1,28 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkOption types concatStringsSep;
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkEnableOption
|
||||
mkOption
|
||||
types
|
||||
concatStringsSep
|
||||
;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
cfg = config.boot.loader.fit;
|
||||
o = config.system.outputs;
|
||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||
wantsDtb = config.hardware.dts ? src && config.hardware.dts.src != null;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options.boot.loader.fit.enable = mkEnableOption "FIT in /boot";
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
system.outputs.bootfiles = pkgs.runCommand "boot-fit" {} ''
|
||||
system.outputs.bootfiles = pkgs.runCommand "boot-fit" { } ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
cp ${o.uimage} fit
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
@@ -21,17 +21,20 @@ in
|
||||
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
|
||||
'';
|
||||
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
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
@@ -23,16 +23,19 @@ in
|
||||
rootfs =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand e2fsprogs;
|
||||
in runCommand "mkfs.ext4" {
|
||||
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
|
||||
mke2fs -t ext4 -j -d $tree $out
|
||||
'';
|
||||
in
|
||||
runCommand "mkfs.ext4"
|
||||
{
|
||||
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
|
||||
mke2fs -t ext4 -j -d $tree $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,11 +1,16 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkOption mkIf types;
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkOption
|
||||
mkIf
|
||||
types
|
||||
;
|
||||
inherit (pkgs) runCommand;
|
||||
in
|
||||
{
|
||||
@@ -29,13 +34,15 @@ in
|
||||
kernel.config = {
|
||||
BLK_DEV_INITRD = "y";
|
||||
INITRAMFS_SOURCE = builtins.toJSON "${config.system.outputs.initramfs}";
|
||||
# INITRAMFS_COMPRESSION_LZO = "y";
|
||||
# INITRAMFS_COMPRESSION_LZO = "y";
|
||||
};
|
||||
|
||||
system.outputs = {
|
||||
initramfs =
|
||||
let inherit (pkgs.pkgsBuildBuild) gen_init_cpio;
|
||||
in runCommand "initramfs.cpio" {} ''
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) gen_init_cpio;
|
||||
in
|
||||
runCommand "initramfs.cpio" { } ''
|
||||
cat << SPECIALS | ${gen_init_cpio}/bin/gen_init_cpio /dev/stdin > $out
|
||||
dir /proc 0755 0 0
|
||||
dir /dev 0755 0 0
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
@@ -27,14 +27,16 @@ in
|
||||
rootfs =
|
||||
let
|
||||
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 )
|
||||
'';
|
||||
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 )
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,14 +1,15 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
o = config.system.outputs;
|
||||
phram_address = lib.toHexString (config.hardware.ram.startAddress + 256 * 1024 * 1024);
|
||||
in {
|
||||
in
|
||||
{
|
||||
options.system.outputs = {
|
||||
mbrimage = mkOption {
|
||||
type = types.package;
|
||||
@@ -20,7 +21,7 @@ in {
|
||||
the contents of ``outputs.rootfs`` as its only partition.
|
||||
'';
|
||||
};
|
||||
vmdisk = mkOption { type = types.package; };
|
||||
vmdisk = mkOption { type = types.package; };
|
||||
};
|
||||
|
||||
config = {
|
||||
@@ -28,15 +29,18 @@ in {
|
||||
mbrimage =
|
||||
let
|
||||
o = config.system.outputs;
|
||||
in pkgs.runCommand "mbrimage" {
|
||||
depsBuildBuild = [ pkgs.pkgsBuildBuild.util-linux ];
|
||||
} ''
|
||||
# leave 4 sectors at start for partition table
|
||||
# and alignment to 2048 bytes (does that help?)
|
||||
dd if=${o.rootfs} of=$out bs=512 seek=4 conv=sync
|
||||
echo '4,-,L,*' | sfdisk $out
|
||||
'';
|
||||
vmdisk = pkgs.runCommand "vmdisk" {} ''
|
||||
in
|
||||
pkgs.runCommand "mbrimage"
|
||||
{
|
||||
depsBuildBuild = [ pkgs.pkgsBuildBuild.util-linux ];
|
||||
}
|
||||
''
|
||||
# leave 4 sectors at start for partition table
|
||||
# and alignment to 2048 bytes (does that help?)
|
||||
dd if=${o.rootfs} of=$out bs=512 seek=4 conv=sync
|
||||
echo '4,-,L,*' | sfdisk $out
|
||||
'';
|
||||
vmdisk = pkgs.runCommand "vmdisk" { } ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
ln -s ${o.mbrimage} ./mbrimage
|
||||
|
@@ -1,17 +1,18 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
inherit (config.boot) tftp;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options.system.outputs = {
|
||||
firmware = mkOption {
|
||||
type = types.package;
|
||||
internal = true; # component of mtdimage
|
||||
internal = true; # component of mtdimage
|
||||
description = ''
|
||||
Binary image (combining kernel, FDT, rootfs, initramfs
|
||||
if needed, etc) for the target device.
|
||||
@@ -19,7 +20,7 @@ in {
|
||||
};
|
||||
flash-scr = mkOption {
|
||||
type = types.package;
|
||||
internal = true; # component of mtdimage
|
||||
internal = true; # component of mtdimage
|
||||
description = ''
|
||||
Copy-pastable U-Boot commands to TFTP download the
|
||||
image and write it to flash
|
||||
@@ -60,13 +61,15 @@ in {
|
||||
|
||||
config = {
|
||||
kernel = {
|
||||
config = {
|
||||
# this needs to be conditional on "not qemu"
|
||||
MTD_SPLIT_UIMAGE_FW = "y";
|
||||
} // lib.optionalAttrs (pkgs.stdenv.isMips) {
|
||||
# https://stackoverflow.com/questions/26466470/can-the-logical-erase-block-size-of-an-mtd-device-be-increased
|
||||
MTD_SPI_NOR_USE_4K_SECTORS = "n";
|
||||
};
|
||||
config =
|
||||
{
|
||||
# this needs to be conditional on "not qemu"
|
||||
MTD_SPLIT_UIMAGE_FW = "y";
|
||||
}
|
||||
// lib.optionalAttrs (pkgs.stdenv.isMips) {
|
||||
# https://stackoverflow.com/questions/26466470/can-the-logical-erase-block-size-of-an-mtd-device-be-increased
|
||||
MTD_SPI_NOR_USE_4K_SECTORS = "n";
|
||||
};
|
||||
};
|
||||
|
||||
programs.busybox.applets = [
|
||||
@@ -78,14 +81,17 @@ in {
|
||||
let
|
||||
o = config.system.outputs;
|
||||
bs = toString config.hardware.flash.eraseBlockSize;
|
||||
in pkgs.runCommand "firmware" {} ''
|
||||
in
|
||||
pkgs.runCommand "firmware" { } ''
|
||||
dd if=${o.uimage} of=$out bs=${bs} conv=sync
|
||||
dd if=${o.rootfs} of=$out bs=${bs} conv=sync,nocreat,notrunc oflag=append
|
||||
'';
|
||||
mtdimage =
|
||||
let o = config.system.outputs; in
|
||||
let
|
||||
o = config.system.outputs;
|
||||
in
|
||||
# could use trivial-builders.linkFarmFromDrvs here?
|
||||
pkgs.runCommand "mtdimage" {} ''
|
||||
pkgs.runCommand "mtdimage" { } ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
ln -s ${o.firmware} firmware.bin
|
||||
@@ -96,24 +102,24 @@ in {
|
||||
ln -s ${o.uimage} uimage
|
||||
ln -s ${o.dtb} dtb
|
||||
ln -s ${o.flash-scr} flash.scr
|
||||
'';
|
||||
'';
|
||||
|
||||
flash-scr =
|
||||
let
|
||||
inherit (pkgs.lib.trivial) toHexString;
|
||||
inherit (config.hardware) flash;
|
||||
in
|
||||
pkgs.buildPackages.runCommand "" {} ''
|
||||
imageSize=$(stat -L -c %s ${config.system.outputs.firmware})
|
||||
cat > $out << EOF
|
||||
setenv serverip ${tftp.serverip}
|
||||
setenv ipaddr ${tftp.ipaddr}
|
||||
tftp 0x${toHexString tftp.loadAddress} result/firmware.bin
|
||||
erase 0x${toHexString flash.address} +0x${toHexString flash.size}
|
||||
cp.b 0x${toHexString tftp.loadAddress} 0x${toHexString flash.address} \''${filesize}
|
||||
echo command line was ${builtins.toJSON (concatStringsSep " " config.boot.commandLine)}
|
||||
EOF
|
||||
'';
|
||||
pkgs.buildPackages.runCommand "" { } ''
|
||||
imageSize=$(stat -L -c %s ${config.system.outputs.firmware})
|
||||
cat > $out << EOF
|
||||
setenv serverip ${tftp.serverip}
|
||||
setenv ipaddr ${tftp.ipaddr}
|
||||
tftp 0x${toHexString tftp.loadAddress} result/firmware.bin
|
||||
erase 0x${toHexString flash.address} +0x${toHexString flash.size}
|
||||
cp.b 0x${toHexString tftp.loadAddress} 0x${toHexString flash.address} \''${filesize}
|
||||
echo command line was ${builtins.toJSON (concatStringsSep " " config.boot.commandLine)}
|
||||
EOF
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -10,8 +10,7 @@ let
|
||||
in
|
||||
{
|
||||
config = mkIf (config.rootfsType == "squashfs") {
|
||||
system.outputs.rootfs =
|
||||
liminix.builders.squashfs config.filesystem.contents;
|
||||
system.outputs.rootfs = liminix.builders.squashfs config.filesystem.contents;
|
||||
kernel.config = {
|
||||
SQUASHFS = "y";
|
||||
SQUASHFS_XZ = "y";
|
||||
|
@@ -1,11 +1,16 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkOption mkIf types;
|
||||
inherit (lib)
|
||||
mkEnableOption
|
||||
mkOption
|
||||
mkIf
|
||||
types
|
||||
;
|
||||
inherit (pkgs) runCommand;
|
||||
in
|
||||
{
|
||||
@@ -22,7 +27,6 @@ in
|
||||
};
|
||||
};
|
||||
config = {
|
||||
system.outputs.systemConfiguration =
|
||||
pkgs.systemconfig config.filesystem.contents;
|
||||
system.outputs.systemConfiguration = pkgs.systemconfig config.filesystem.contents;
|
||||
};
|
||||
}
|
||||
|
@@ -1,15 +1,16 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
cfg = config.boot.tftp;
|
||||
hw = config.hardware;
|
||||
arch = pkgs.stdenv.hostPlatform.linuxArch;
|
||||
in {
|
||||
in
|
||||
{
|
||||
imports = [ ../ramdisk.nix ];
|
||||
options.boot.tftp = {
|
||||
freeSpaceBytes = mkOption {
|
||||
@@ -17,7 +18,10 @@ in {
|
||||
default = 0;
|
||||
};
|
||||
kernelFormat = mkOption {
|
||||
type = types.enum [ "zimage" "uimage" ];
|
||||
type = types.enum [
|
||||
"zimage"
|
||||
"uimage"
|
||||
];
|
||||
default = "uimage";
|
||||
};
|
||||
compressRoot = mkOption {
|
||||
@@ -61,14 +65,22 @@ in {
|
||||
assert config.rootfsType != "ubifs";
|
||||
let
|
||||
o = config.system.outputs;
|
||||
image = let choices = {
|
||||
uimage = o.uimage;
|
||||
zimage = o.kernel.zImage;
|
||||
}; in choices.${cfg.kernelFormat};
|
||||
bootCommand = let choices = {
|
||||
uimage = "bootm";
|
||||
zimage = "bootz";
|
||||
}; in choices.${cfg.kernelFormat};
|
||||
image =
|
||||
let
|
||||
choices = {
|
||||
uimage = o.uimage;
|
||||
zimage = o.kernel.zImage;
|
||||
};
|
||||
in
|
||||
choices.${cfg.kernelFormat};
|
||||
bootCommand =
|
||||
let
|
||||
choices = {
|
||||
uimage = "bootm";
|
||||
zimage = "bootz";
|
||||
};
|
||||
in
|
||||
choices.${cfg.kernelFormat};
|
||||
|
||||
cmdline = concatStringsSep " " config.boot.commandLine;
|
||||
objcopy = "${pkgs.stdenv.cc.bintools.targetPrefix}objcopy";
|
||||
@@ -77,7 +89,16 @@ in {
|
||||
rm -f vmlinux.bin.lzma ; lzma -k -z vmlinux.bin
|
||||
'';
|
||||
in
|
||||
pkgs.runCommand "tftpboot" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ lzma dtc pkgs.stdenv.cc ubootTools ]; } ''
|
||||
pkgs.runCommand "tftpboot"
|
||||
{
|
||||
nativeBuildInputs = with pkgs.pkgsBuildBuild; [
|
||||
lzma
|
||||
dtc
|
||||
pkgs.stdenv.cc
|
||||
ubootTools
|
||||
];
|
||||
}
|
||||
''
|
||||
mkdir $out
|
||||
cd $out
|
||||
binsize() { local s=$(stat -L -c %s $1); echo $(($s + 0x1000 &(~0xfff))); }
|
||||
@@ -97,17 +118,19 @@ in {
|
||||
# end of the kernel is free
|
||||
|
||||
dtbStart=$(($rootfsStart + $rootfsSize))
|
||||
${if cfg.compressRoot
|
||||
then ''
|
||||
lzma -z9cv ${o.rootfs} > rootfs.lz
|
||||
rootfsLzStart=$dtbStart
|
||||
rootfsLzSize=$(binsize rootfs.lz)
|
||||
dtbStart=$(($dtbStart + $rootfsLzSize))
|
||||
''
|
||||
else ''
|
||||
ln -s ${o.rootfs} rootfs
|
||||
''
|
||||
}
|
||||
${
|
||||
if cfg.compressRoot then
|
||||
''
|
||||
lzma -z9cv ${o.rootfs} > rootfs.lz
|
||||
rootfsLzStart=$dtbStart
|
||||
rootfsLzSize=$(binsize rootfs.lz)
|
||||
dtbStart=$(($dtbStart + $rootfsLzSize))
|
||||
''
|
||||
else
|
||||
''
|
||||
ln -s ${o.rootfs} rootfs
|
||||
''
|
||||
}
|
||||
|
||||
cat ${o.dtb} > dtb
|
||||
address_cells=$(fdtget dtb / '#address-cells')
|
||||
@@ -128,37 +151,40 @@ in {
|
||||
|
||||
dtbSize=$(binsize ./dtb )
|
||||
|
||||
${if cfg.appendDTB then ''
|
||||
imageStart=$dtbStart
|
||||
# re-package image with updated dtb
|
||||
cat ${o.kernel} > vmlinux.elf
|
||||
${objcopy} --update-section .appended_dtb=dtb vmlinux.elf
|
||||
${stripAndZip}
|
||||
mkimage -A ${arch} -O linux -T kernel -C lzma -a $(hex ${toString hw.loadAddress}) -e $(hex ${toString hw.entryPoint}) -n '${lib.toUpper arch} Liminix Linux tftpboot' -d vmlinux.bin.lzma image
|
||||
# dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1
|
||||
tftpcmd="tftpboot $(hex $imageStart) result/image "
|
||||
bootcmd="bootm $(hex $imageStart)"
|
||||
'' else ''
|
||||
imageStart=$(($dtbStart + $dtbSize))
|
||||
tftpcmd="tftpboot $(hex $imageStart) result/image; tftpboot $(hex $dtbStart) result/dtb "
|
||||
ln -s ${image} image
|
||||
bootcmd="${bootCommand} $(hex $imageStart) - $(hex $dtbStart)"
|
||||
''}
|
||||
${
|
||||
if cfg.appendDTB then
|
||||
''
|
||||
imageStart=$dtbStart
|
||||
# re-package image with updated dtb
|
||||
cat ${o.kernel} > vmlinux.elf
|
||||
${objcopy} --update-section .appended_dtb=dtb vmlinux.elf
|
||||
${stripAndZip}
|
||||
mkimage -A ${arch} -O linux -T kernel -C lzma -a $(hex ${toString hw.loadAddress}) -e $(hex ${toString hw.entryPoint}) -n '${lib.toUpper arch} Liminix Linux tftpboot' -d vmlinux.bin.lzma image
|
||||
# dtc -I dtb -O dts -o /dev/stdout dtb | grep -A10 chosen ; exit 1
|
||||
tftpcmd="tftpboot $(hex $imageStart) result/image "
|
||||
bootcmd="bootm $(hex $imageStart)"
|
||||
''
|
||||
else
|
||||
''
|
||||
imageStart=$(($dtbStart + $dtbSize))
|
||||
tftpcmd="tftpboot $(hex $imageStart) result/image; tftpboot $(hex $dtbStart) result/dtb "
|
||||
ln -s ${image} image
|
||||
bootcmd="${bootCommand} $(hex $imageStart) - $(hex $dtbStart)"
|
||||
''
|
||||
}
|
||||
|
||||
cat > boot.scr << EOF
|
||||
setenv serverip ${cfg.serverip}
|
||||
setenv ipaddr ${cfg.ipaddr}
|
||||
${
|
||||
if cfg.compressRoot
|
||||
then "tftpboot $(hex $rootfsLzStart) result/rootfs.lz"
|
||||
else "tftpboot $(hex $rootfsStart) result/rootfs"
|
||||
if cfg.compressRoot then
|
||||
"tftpboot $(hex $rootfsLzStart) result/rootfs.lz"
|
||||
else
|
||||
"tftpboot $(hex $rootfsStart) result/rootfs"
|
||||
}; $tftpcmd
|
||||
${if cfg.compressRoot
|
||||
then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); "
|
||||
else ""
|
||||
} $bootcmd
|
||||
${if cfg.compressRoot then "lzmadec $(hex $rootfsLzStart) $(hex $rootfsStart); " else ""} $bootcmd
|
||||
EOF
|
||||
'';
|
||||
'';
|
||||
|
||||
};
|
||||
};
|
||||
|
@@ -1,14 +1,15 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
o = config.system.outputs;
|
||||
cfg = config.tplink-safeloader;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options.tplink-safeloader = {
|
||||
board = mkOption {
|
||||
type = types.str;
|
||||
@@ -53,9 +54,10 @@ in {
|
||||
config = {
|
||||
system.outputs = rec {
|
||||
tplink-safeloader =
|
||||
pkgs.runCommand "tplink" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ firmware-utils ]; } ''
|
||||
tplink-safeloader -B "${cfg.board}" -k "${o.uimage}" -r "${o.rootfs}" -o $out
|
||||
'';
|
||||
pkgs.runCommand "tplink" { nativeBuildInputs = with pkgs.pkgsBuildBuild; [ firmware-utils ]; }
|
||||
''
|
||||
tplink-safeloader -B "${cfg.board}" -k "${o.uimage}" -r "${o.rootfs}" -o $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
@@ -15,7 +15,7 @@ in
|
||||
|
||||
config = mkIf (config.rootfsType == "ubifs") {
|
||||
kernel.config = {
|
||||
MTD_UBI="y";
|
||||
MTD_UBI = "y";
|
||||
UBIFS_FS = "y";
|
||||
UBIFS_FS_SECURITY = "n";
|
||||
};
|
||||
@@ -25,13 +25,16 @@ in
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand mtdutils;
|
||||
cfg = config.hardware.ubi;
|
||||
in runCommand "mkfs.ubifs" {
|
||||
depsBuildBuild = [ mtdutils ];
|
||||
} ''
|
||||
mkdir tmp
|
||||
tree=${o.bootablerootdir}
|
||||
mkfs.ubifs -x favor_lzo -c ${cfg.maxLEBcount} -m ${cfg.minIOSize} -e ${cfg.logicalEraseBlockSize} -y -r $tree --output $out --squash-uids -o $out
|
||||
'';
|
||||
in
|
||||
runCommand "mkfs.ubifs"
|
||||
{
|
||||
depsBuildBuild = [ mtdutils ];
|
||||
}
|
||||
''
|
||||
mkdir tmp
|
||||
tree=${o.bootablerootdir}
|
||||
mkfs.ubifs -x favor_lzo -c ${cfg.maxLEBcount} -m ${cfg.minIOSize} -e ${cfg.logicalEraseBlockSize} -y -r $tree --output $out --squash-uids -o $out
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
@@ -13,108 +13,111 @@ let
|
||||
setenv loadaddr ${lib.toHexString cfg.loadAddress}
|
||||
tftpboot $loadaddr result/rootfs
|
||||
ubi write $loadaddr liminix $filesize
|
||||
'';
|
||||
in {
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.system.outputs = {
|
||||
ubimage = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
ubimage
|
||||
*******
|
||||
ubimage
|
||||
*******
|
||||
|
||||
This output provides a UBIFS filesystem image and a small U-Boot script
|
||||
to make the manual installation process very slightly simpler. You will
|
||||
need a serial connection and a network connection to a TFTP server
|
||||
containing the filesystem image it creates.
|
||||
This output provides a UBIFS filesystem image and a small U-Boot script
|
||||
to make the manual installation process very slightly simpler. You will
|
||||
need a serial connection and a network connection to a TFTP server
|
||||
containing the filesystem image it creates.
|
||||
|
||||
.. warning:: These steps were tested on a Belkin RT3200 (also known as
|
||||
Linksys E8450). Other devices may be set up differently,
|
||||
so use them as inspiration and don't just paste them
|
||||
blindly.
|
||||
.. warning:: These steps were tested on a Belkin RT3200 (also known as
|
||||
Linksys E8450). Other devices may be set up differently,
|
||||
so use them as inspiration and don't just paste them
|
||||
blindly.
|
||||
|
||||
1) determine which MTD device is being used for UBI, and the partition name:
|
||||
1) determine which MTD device is being used for UBI, and the partition name:
|
||||
|
||||
.. code-block:: console
|
||||
.. code-block:: console
|
||||
|
||||
uboot> ubi part
|
||||
Device 0: ubi0, MTD partition ubi
|
||||
uboot> ubi part
|
||||
Device 0: ubi0, MTD partition ubi
|
||||
|
||||
In this case the important value is ``ubi0``
|
||||
In this case the important value is ``ubi0``
|
||||
|
||||
2) list the available volumes and create a new one on which to install Liminix
|
||||
2) list the available volumes and create a new one on which to install Liminix
|
||||
|
||||
.. code-block:: console
|
||||
.. code-block:: console
|
||||
|
||||
uboot> ubi info l
|
||||
[ copious output scrolls past ]
|
||||
uboot> ubi info l
|
||||
[ copious output scrolls past ]
|
||||
|
||||
Expect there to be existing volumes and for some or all of them to be
|
||||
important. Unless you know what you're doing, don't remove anything
|
||||
whose name suggests it's related to uboot, or any kind of backup or
|
||||
recovery partition. To see how much space is free:
|
||||
Expect there to be existing volumes and for some or all of them to be
|
||||
important. Unless you know what you're doing, don't remove anything
|
||||
whose name suggests it's related to uboot, or any kind of backup or
|
||||
recovery partition. To see how much space is free:
|
||||
|
||||
.. code-block:: console
|
||||
.. code-block:: console
|
||||
|
||||
uboot> ubi info
|
||||
[ ... ]
|
||||
UBI: available PEBs: 823
|
||||
uboot> ubi info
|
||||
[ ... ]
|
||||
UBI: available PEBs: 823
|
||||
|
||||
Now we can make our new root volume
|
||||
Now we can make our new root volume
|
||||
|
||||
.. code-block:: console
|
||||
.. code-block:: console
|
||||
|
||||
uboot> ubi create liminix -
|
||||
uboot> ubi create liminix -
|
||||
|
||||
3) transfer the root filesystem from the build system and write it to
|
||||
the new volume. Paste the contents of :file:`result/flash.scr` one line at a time
|
||||
into U-Boot:
|
||||
3) transfer the root filesystem from the build system and write it to
|
||||
the new volume. Paste the contents of :file:`result/flash.scr` one line at a time
|
||||
into U-Boot:
|
||||
|
||||
.. code-block:: console
|
||||
.. code-block:: console
|
||||
|
||||
uboot> setenv serverip 10.0.0.1
|
||||
uboot> setenv ipaddr 10.0.0.8
|
||||
uboot> setenv loadaddr 4007FF28
|
||||
uboot> tftpboot $loadaddr result/rootfs
|
||||
uboot> ubi write $loadaddr liminix $filesize
|
||||
uboot> setenv serverip 10.0.0.1
|
||||
uboot> setenv ipaddr 10.0.0.8
|
||||
uboot> setenv loadaddr 4007FF28
|
||||
uboot> tftpboot $loadaddr result/rootfs
|
||||
uboot> ubi write $loadaddr liminix $filesize
|
||||
|
||||
Now we have the root filesystem installed on the device. You
|
||||
can even mount it and poke around using :command:`ubifsmount ubi0:liminix; ubifsls /`
|
||||
Now we have the root filesystem installed on the device. You
|
||||
can even mount it and poke around using :command:`ubifsmount ubi0:liminix; ubifsls /`
|
||||
|
||||
4) optional: before you configure the device to boot into Liminix
|
||||
automatically, you can try booting it by hand to see if it works:
|
||||
4) optional: before you configure the device to boot into Liminix
|
||||
automatically, you can try booting it by hand to see if it works:
|
||||
|
||||
.. code-block:: console
|
||||
.. code-block:: console
|
||||
|
||||
uboot> ubifsmount ubi0:liminix
|
||||
uboot> ubifsload ''${loadaddr} boot/fit
|
||||
uboot> bootm ''${loadaddr}
|
||||
uboot> ubifsmount ubi0:liminix
|
||||
uboot> ubifsload ''${loadaddr} boot/fit
|
||||
uboot> bootm ''${loadaddr}
|
||||
|
||||
Once you've done this and you're happy with it, reset the device to
|
||||
return to U-Boot.
|
||||
Once you've done this and you're happy with it, reset the device to
|
||||
return to U-Boot.
|
||||
|
||||
5) Instructions for configuring autoboot are likely to be very
|
||||
device-dependent and you should consult the Liminix documentation for
|
||||
your device. (If you're bringing up a new device, some detective work
|
||||
may be needed. Try running `printenv` and trace through the flow of
|
||||
execution from (probably) :command:`$bootcmd` and look for a suitable
|
||||
variable to change)
|
||||
5) Instructions for configuring autoboot are likely to be very
|
||||
device-dependent and you should consult the Liminix documentation for
|
||||
your device. (If you're bringing up a new device, some detective work
|
||||
may be needed. Try running `printenv` and trace through the flow of
|
||||
execution from (probably) :command:`$bootcmd` and look for a suitable
|
||||
variable to change)
|
||||
|
||||
6) Now you can reboot the device into Liminix
|
||||
6) Now you can reboot the device into Liminix
|
||||
|
||||
.. code-block:: console
|
||||
.. code-block:: console
|
||||
|
||||
uboot> reset
|
||||
uboot> reset
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config.system.outputs.ubimage =
|
||||
assert config.rootfsType == "ubifs";
|
||||
let o = config.system.outputs; in
|
||||
pkgs.runCommand "ubimage" {} ''
|
||||
let
|
||||
o = config.system.outputs;
|
||||
in
|
||||
pkgs.runCommand "ubimage" { } ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
ln -s ${o.rootfs} rootfs
|
||||
ln -s ${instructions} flash.scr
|
||||
'';
|
||||
'';
|
||||
}
|
||||
|
@@ -1,93 +1,112 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkOption types concatStringsSep optionalString;
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkOption
|
||||
types
|
||||
concatStringsSep
|
||||
optionalString
|
||||
;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./initramfs.nix
|
||||
./ubifs.nix
|
||||
];
|
||||
{
|
||||
imports = [
|
||||
./initramfs.nix
|
||||
./ubifs.nix
|
||||
];
|
||||
|
||||
options.hardware.ubi = {
|
||||
minIOSize = mkOption { type = types.str; };
|
||||
eraseBlockSize = mkOption { type = types.str; }; # LEB
|
||||
maxLEBcount = mkOption { type = types.str; }; # LEB
|
||||
};
|
||||
options.system.outputs.ubivolume = mkOption {
|
||||
type = types.package;
|
||||
options.hardware.ubi = {
|
||||
minIOSize = mkOption { type = types.str; };
|
||||
eraseBlockSize = mkOption { type = types.str; }; # LEB
|
||||
maxLEBcount = mkOption { type = types.str; }; # LEB
|
||||
};
|
||||
options.system.outputs.ubivolume = mkOption {
|
||||
type = types.package;
|
||||
};
|
||||
|
||||
config = mkIf (config.rootfsType == "ubifs") {
|
||||
kernel.config = {
|
||||
MTD_UBI = "y";
|
||||
|
||||
UBIFS_FS = "y";
|
||||
UBIFS_FS_SECURITY = "n";
|
||||
};
|
||||
boot.initramfs.enable = true;
|
||||
|
||||
config = mkIf (config.rootfsType == "ubifs") {
|
||||
kernel.config = {
|
||||
MTD_UBI="y";
|
||||
|
||||
UBIFS_FS = "y";
|
||||
UBIFS_FS_SECURITY = "n";
|
||||
};
|
||||
boot.initramfs.enable = true;
|
||||
|
||||
system.outputs.ubivolume =
|
||||
system.outputs.ubivolume =
|
||||
let
|
||||
inherit (pkgs.pkgsBuildBuild) runCommand;
|
||||
ubiVolume = ({ name, volumeId, image, flags ? [] }:
|
||||
''
|
||||
[${name}]
|
||||
mode=ubi
|
||||
vol_id=${toString volumeId}
|
||||
vol_type=dynamic
|
||||
vol_name=${name}
|
||||
vol_alignment=1
|
||||
${optionalString (image != null) ''
|
||||
image=${image}
|
||||
''}
|
||||
${optionalString (image == null) ''
|
||||
vol_size=1MiB
|
||||
''}
|
||||
${optionalString (flags != []) ''
|
||||
vol_flags=${concatStringsSep "," flags}
|
||||
''}
|
||||
'');
|
||||
ubiVolume = (
|
||||
{
|
||||
name,
|
||||
volumeId,
|
||||
image,
|
||||
flags ? [ ],
|
||||
}:
|
||||
''
|
||||
[${name}]
|
||||
mode=ubi
|
||||
vol_id=${toString volumeId}
|
||||
vol_type=dynamic
|
||||
vol_name=${name}
|
||||
vol_alignment=1
|
||||
${optionalString (image != null) ''
|
||||
image=${image}
|
||||
''}
|
||||
${optionalString (image == null) ''
|
||||
vol_size=1MiB
|
||||
''}
|
||||
${optionalString (flags != [ ]) ''
|
||||
vol_flags=${concatStringsSep "," flags}
|
||||
''}
|
||||
''
|
||||
);
|
||||
|
||||
ubiImage = (volumes:
|
||||
let
|
||||
ubinizeConfig = pkgs.writeText "ubinize.conf" (concatStringsSep "\n" volumes);
|
||||
inherit (pkgs.pkgsBuildBuild) mtdutils;
|
||||
in
|
||||
runCommand "ubinize" {
|
||||
depsBuildBuild = [ mtdutils ];
|
||||
# block size := 128kb
|
||||
# page size := 2048
|
||||
# ubninize opts := -E 5
|
||||
} ''
|
||||
ubinize -Q "$SOURCE_DATE_EPOCH" -o $out \
|
||||
-p ${config.hardware.ubi.physicalEraseBlockSize} -m ${config.hardware.ubi.minIOSize} \
|
||||
-e ${config.hardware.ubi.logicalEraseBlockSize} \
|
||||
${ubinizeConfig}
|
||||
'');
|
||||
ubiImage = (
|
||||
volumes:
|
||||
let
|
||||
ubinizeConfig = pkgs.writeText "ubinize.conf" (concatStringsSep "\n" volumes);
|
||||
inherit (pkgs.pkgsBuildBuild) mtdutils;
|
||||
in
|
||||
runCommand "ubinize"
|
||||
{
|
||||
depsBuildBuild = [ mtdutils ];
|
||||
# block size := 128kb
|
||||
# page size := 2048
|
||||
# ubninize opts := -E 5
|
||||
}
|
||||
''
|
||||
ubinize -Q "$SOURCE_DATE_EPOCH" -o $out \
|
||||
-p ${config.hardware.ubi.physicalEraseBlockSize} -m ${config.hardware.ubi.minIOSize} \
|
||||
-e ${config.hardware.ubi.logicalEraseBlockSize} \
|
||||
${ubinizeConfig}
|
||||
''
|
||||
);
|
||||
|
||||
ubiDisk = ({ initramfs }:
|
||||
let
|
||||
initramfsUbi = ubiVolume {
|
||||
name = "rootfs";
|
||||
volumeId = 0;
|
||||
image = initramfs;
|
||||
flags = [ "autoresize" ];
|
||||
};
|
||||
in
|
||||
ubiDisk = (
|
||||
{ initramfs }:
|
||||
let
|
||||
initramfsUbi = ubiVolume {
|
||||
name = "rootfs";
|
||||
volumeId = 0;
|
||||
image = initramfs;
|
||||
flags = [ "autoresize" ];
|
||||
};
|
||||
in
|
||||
ubiImage [
|
||||
initramfsUbi
|
||||
]);
|
||||
]
|
||||
);
|
||||
|
||||
disk = ubiDisk {
|
||||
initramfs = config.system.outputs.rootfs; # ???
|
||||
};
|
||||
|
||||
in
|
||||
disk;
|
||||
disk;
|
||||
};
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
@@ -25,13 +25,12 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
config.system.outputs.updater =
|
||||
runCommand "buildUpdater" { } ''
|
||||
mkdir -p $out/bin $out/etc
|
||||
cp ${o.kernel.config} $out/etc/kconfig
|
||||
substitute ${./update.sh} $out/bin/update.sh \
|
||||
--subst-var-by toplevel ${o.systemConfiguration} \
|
||||
--subst-var-by min_copy_closure ${min-copy-closure}
|
||||
chmod +x $out/bin/update.sh
|
||||
'';
|
||||
config.system.outputs.updater = runCommand "buildUpdater" { } ''
|
||||
mkdir -p $out/bin $out/etc
|
||||
cp ${o.kernel.config} $out/etc/kconfig
|
||||
substitute ${./update.sh} $out/bin/update.sh \
|
||||
--subst-var-by toplevel ${o.systemConfiguration} \
|
||||
--subst-var-by min_copy_closure ${min-copy-closure}
|
||||
chmod +x $out/bin/update.sh
|
||||
'';
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types concatStringsSep;
|
||||
@@ -49,12 +49,15 @@ in
|
||||
let
|
||||
inherit (config.system.outputs) rootfs kernel manifest;
|
||||
cmdline = builtins.toJSON (concatStringsSep " " config.boot.commandLine);
|
||||
makeBootableImage = pkgs.runCommandCC "objcopy" {}
|
||||
(if pkgs.stdenv.hostPlatform.isAarch
|
||||
then "${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -R .comment -S ${kernel} $out"
|
||||
else "cp ${kernel} $out");
|
||||
makeBootableImage = pkgs.runCommandCC "objcopy" { } (
|
||||
if pkgs.stdenv.hostPlatform.isAarch then
|
||||
"${pkgs.stdenv.cc.targetPrefix}objcopy -O binary -R .comment -S ${kernel} $out"
|
||||
else
|
||||
"cp ${kernel} $out"
|
||||
);
|
||||
phram_address = lib.toHexString (config.hardware.ram.startAddress + 256 * 1024 * 1024);
|
||||
in pkgs.runCommand "vmroot" {} ''
|
||||
in
|
||||
pkgs.runCommand "vmroot" { } ''
|
||||
mkdir $out
|
||||
cd $out
|
||||
ln -s ${rootfs} rootfs
|
||||
@@ -67,7 +70,7 @@ in
|
||||
${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
|
||||
chmod +x run.sh
|
||||
'';
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,25 +1,26 @@
|
||||
{
|
||||
config
|
||||
, pkgs
|
||||
, lib
|
||||
, ...
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
models = "6b e1 6f e1 ff ff ff ff ff ff";
|
||||
in {
|
||||
in
|
||||
{
|
||||
options.system.outputs = {
|
||||
zyxel-nwa-fit = mkOption {
|
||||
type = types.package;
|
||||
description = ''
|
||||
zyxel-nwa-fit
|
||||
*************
|
||||
zyxel-nwa-fit
|
||||
*************
|
||||
|
||||
This output provides a FIT image for Zyxel NWA series
|
||||
containing a kernel image and an UBIFS rootfs.
|
||||
This output provides a FIT image for Zyxel NWA series
|
||||
containing a kernel image and an UBIFS rootfs.
|
||||
|
||||
It can usually be used as a factory image to install Liminix
|
||||
on a system with pre-existing firmware and OS.
|
||||
It can usually be used as a factory image to install Liminix
|
||||
on a system with pre-existing firmware and OS.
|
||||
'';
|
||||
};
|
||||
};
|
||||
@@ -34,38 +35,43 @@ on a system with pre-existing firmware and OS.
|
||||
let
|
||||
o = config.system.outputs;
|
||||
# 8129kb padding.
|
||||
paddedKernel = pkgs.runCommand "padded-kernel" {} ''
|
||||
paddedKernel = pkgs.runCommand "padded-kernel" { } ''
|
||||
cp --no-preserve=mode ${o.uimage} $out
|
||||
dd if=/dev/zero of=$out bs=1 count=1 seek=8388607
|
||||
'';
|
||||
firmwareImage = pkgs.runCommand "firmware-image" {} ''
|
||||
firmwareImage = pkgs.runCommand "firmware-image" { } ''
|
||||
cat ${paddedKernel} ${o.ubivolume} > $out
|
||||
'';
|
||||
dts = pkgs.writeText "image.its" ''
|
||||
/dts-v1/;
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
description = "Zyxel FIT (Flattened Image Tree)";
|
||||
compat-models = [${models}];
|
||||
#address-cells = <1>;
|
||||
/ {
|
||||
description = "Zyxel FIT (Flattened Image Tree)";
|
||||
compat-models = [${models}];
|
||||
#address-cells = <1>;
|
||||
|
||||
images {
|
||||
firmware {
|
||||
data = /incbin/("${firmwareImage}");
|
||||
type = "firmware";
|
||||
compression = "none";
|
||||
hash@1 {
|
||||
algo = "sha1";
|
||||
images {
|
||||
firmware {
|
||||
data = /incbin/("${firmwareImage}");
|
||||
type = "firmware";
|
||||
compression = "none";
|
||||
hash@1 {
|
||||
algo = "sha1";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
'';
|
||||
'';
|
||||
in
|
||||
pkgs.runCommand "zyxel-nwa-fit-${config.boot.imageType}" {
|
||||
nativeBuildInputs = [ pkgs.pkgsBuildBuild.ubootTools pkgs.pkgsBuildBuild.dtc ];
|
||||
} ''
|
||||
mkimage -f ${dts} $out
|
||||
'';
|
||||
pkgs.runCommand "zyxel-nwa-fit-${config.boot.imageType}"
|
||||
{
|
||||
nativeBuildInputs = [
|
||||
pkgs.pkgsBuildBuild.ubootTools
|
||||
pkgs.pkgsBuildBuild.dtc
|
||||
];
|
||||
}
|
||||
''
|
||||
mkimage -f ${dts} $out
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
@@ -1,20 +1,32 @@
|
||||
{ writeAshScript, liminix, svc, lib, serviceFns, output-template }:
|
||||
{
|
||||
writeAshScript,
|
||||
liminix,
|
||||
svc,
|
||||
lib,
|
||||
serviceFns,
|
||||
output-template,
|
||||
}:
|
||||
{
|
||||
command,
|
||||
name,
|
||||
debug
|
||||
, username,
|
||||
debug,
|
||||
username,
|
||||
password,
|
||||
lcpEcho,
|
||||
ppp-options,
|
||||
dependencies ? []
|
||||
} :
|
||||
dependencies ? [ ],
|
||||
}:
|
||||
let
|
||||
inherit (lib) optional optionals escapeShellArgs concatStringsSep;
|
||||
inherit (lib)
|
||||
optional
|
||||
optionals
|
||||
escapeShellArgs
|
||||
concatStringsSep
|
||||
;
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (builtins) toJSON toString typeOf;
|
||||
|
||||
ip-up = writeAshScript "ip-up" {} ''
|
||||
ip-up = writeAshScript "ip-up" { } ''
|
||||
exec >&5 2>&5
|
||||
. ${serviceFns}
|
||||
in_outputs ${name}
|
||||
@@ -28,7 +40,7 @@ let
|
||||
if test -n "''${DNS2}" ;then echo ''${DNS2} > ns2 ; fi
|
||||
test -e ipv6-address && echo >/proc/self/fd/10
|
||||
'';
|
||||
ip6-up = writeAshScript "ip6-up" {} ''
|
||||
ip6-up = writeAshScript "ip6-up" { } ''
|
||||
exec >&5 2>&5
|
||||
. ${serviceFns}
|
||||
in_outputs ${name}
|
||||
@@ -37,35 +49,61 @@ let
|
||||
test -e ifname && echo >/proc/self/fd/10
|
||||
'';
|
||||
literal_or_output =
|
||||
let v = o: ({
|
||||
string = toJSON;
|
||||
int = toJSON;
|
||||
lambda = (o: "output(${toJSON (o "service")}, ${toJSON (o "path")})");
|
||||
}.${typeOf o}) o;
|
||||
in o: "{{ ${v o} }}";
|
||||
let
|
||||
v =
|
||||
o:
|
||||
(
|
||||
{
|
||||
string = toJSON;
|
||||
int = toJSON;
|
||||
lambda = (o: "output(${toJSON (o "service")}, ${toJSON (o "path")})");
|
||||
}
|
||||
.${typeOf o}
|
||||
)
|
||||
o;
|
||||
in
|
||||
o: "{{ ${v o} }}";
|
||||
|
||||
ppp-options' =
|
||||
["+ipv6" "noauth"]
|
||||
[
|
||||
"+ipv6"
|
||||
"noauth"
|
||||
]
|
||||
++ optional debug "debug"
|
||||
++ optionals (username != null) ["name" (literal_or_output username)]
|
||||
++ optionals (password != null) ["password" (literal_or_output password)]
|
||||
++ optionals (username != null) [
|
||||
"name"
|
||||
(literal_or_output username)
|
||||
]
|
||||
++ optionals (password != null) [
|
||||
"password"
|
||||
(literal_or_output password)
|
||||
]
|
||||
++ optional lcpEcho.adaptive "lcp-echo-adaptive"
|
||||
++ optionals (lcpEcho.interval != null)
|
||||
["lcp-echo-interval" (toString lcpEcho.interval)]
|
||||
++ optionals (lcpEcho.failure != null)
|
||||
["lcp-echo-failure" (toString lcpEcho.failure)]
|
||||
++ optionals (lcpEcho.interval != null) [
|
||||
"lcp-echo-interval"
|
||||
(toString lcpEcho.interval)
|
||||
]
|
||||
++ optionals (lcpEcho.failure != null) [
|
||||
"lcp-echo-failure"
|
||||
(toString lcpEcho.failure)
|
||||
]
|
||||
++ ppp-options
|
||||
++ ["ip-up-script" ip-up
|
||||
"ipv6-up-script" ip6-up
|
||||
"ipparam" name
|
||||
"nodetach"
|
||||
# usepeerdns requests DNS servers from peer (which is good),
|
||||
# then attempts to write them to /nix/store/xxxx/ppp/resolv.conf
|
||||
# which causes an unsightly but inconsequential error message
|
||||
"usepeerdns"
|
||||
"nodefaultroute"
|
||||
"logfd" "2"
|
||||
];
|
||||
++ [
|
||||
"ip-up-script"
|
||||
ip-up
|
||||
"ipv6-up-script"
|
||||
ip6-up
|
||||
"ipparam"
|
||||
name
|
||||
"nodetach"
|
||||
# usepeerdns requests DNS servers from peer (which is good),
|
||||
# then attempts to write them to /nix/store/xxxx/ppp/resolv.conf
|
||||
# which causes an unsightly but inconsequential error message
|
||||
"usepeerdns"
|
||||
"nodefaultroute"
|
||||
"logfd"
|
||||
"2"
|
||||
];
|
||||
service = longrun {
|
||||
inherit name;
|
||||
run = ''
|
||||
@@ -77,12 +115,15 @@ let
|
||||
${command}
|
||||
'';
|
||||
notification-fd = 10;
|
||||
timeout-up = if lcpEcho.failure != null
|
||||
then (10 + lcpEcho.failure * lcpEcho.interval) * 1000
|
||||
else 60 * 1000;
|
||||
timeout-up =
|
||||
if lcpEcho.failure != null then (10 + lcpEcho.failure * lcpEcho.interval) * 1000 else 60 * 1000;
|
||||
inherit dependencies;
|
||||
};
|
||||
in svc.secrets.subscriber.build {
|
||||
watch = lib.filter (n: typeOf n=="lambda") [ username password ];
|
||||
in
|
||||
svc.secrets.subscriber.build {
|
||||
watch = lib.filter (n: typeOf n == "lambda") [
|
||||
username
|
||||
password
|
||||
];
|
||||
inherit service;
|
||||
}
|
||||
|
@@ -13,18 +13,24 @@
|
||||
## conjunction with a DHCP uplink, or other more creative forms of
|
||||
## network connection
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
mkStringOption =
|
||||
description: mkOption {
|
||||
description:
|
||||
mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
inherit description;
|
||||
};
|
||||
in {
|
||||
in
|
||||
{
|
||||
imports = [ ../secrets ];
|
||||
options = {
|
||||
system.service.pppoe = mkOption {
|
||||
@@ -61,7 +67,7 @@ in {
|
||||
default = 3;
|
||||
description = "send an LCP echo-request frame to the peer every n seconds";
|
||||
};
|
||||
failure = mkOption {
|
||||
failure = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = 3;
|
||||
description = "terminate connection if n LCP echo-requests are sent without receiving a valid LCP echo-reply";
|
||||
@@ -75,7 +81,7 @@ in {
|
||||
ppp-options = mkOption {
|
||||
type = types.listOf types.str;
|
||||
description = "options supplied on ppp command line";
|
||||
default = [];
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
system.service.l2tp = config.system.callService ./l2tp.nix {
|
||||
@@ -104,7 +110,7 @@ in {
|
||||
default = 3;
|
||||
description = "send an LCP echo-request frame to the peer every n seconds";
|
||||
};
|
||||
failure = mkOption {
|
||||
failure = mkOption {
|
||||
type = types.nullOr types.int;
|
||||
default = 3;
|
||||
description = "terminate connection if n LCP echo-requests are sent without receiving a valid LCP echo-reply";
|
||||
@@ -117,7 +123,7 @@ in {
|
||||
};
|
||||
ppp-options = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
default = [ ];
|
||||
description = "options supplied on ppp command line";
|
||||
};
|
||||
};
|
||||
|
@@ -7,14 +7,15 @@
|
||||
writeAshScript,
|
||||
writeText,
|
||||
xl2tpd,
|
||||
callPackage
|
||||
} :
|
||||
{ lns,
|
||||
callPackage,
|
||||
}:
|
||||
{
|
||||
lns,
|
||||
ppp-options,
|
||||
lcpEcho,
|
||||
username,
|
||||
password,
|
||||
debug
|
||||
debug,
|
||||
}:
|
||||
let
|
||||
name = "${lns}.l2tp";
|
||||
@@ -31,8 +32,16 @@ let
|
||||
max redials = 2 # this gives 1 actual retry, as xl2tpd can't count
|
||||
'';
|
||||
control = "/run/${name}/control";
|
||||
in common {
|
||||
inherit name debug username password lcpEcho ppp-options;
|
||||
in
|
||||
common {
|
||||
inherit
|
||||
name
|
||||
debug
|
||||
username
|
||||
password
|
||||
lcpEcho
|
||||
ppp-options
|
||||
;
|
||||
command = ''
|
||||
touch ${control}
|
||||
exec ${xl2tpd}/bin/xl2tpd -D -p /run/${name}/${name}.pid -c ${conf} -C ${control}
|
||||
|
@@ -7,22 +7,32 @@
|
||||
serviceFns,
|
||||
svc,
|
||||
writeAshScript,
|
||||
callPackage
|
||||
} :
|
||||
{ interface,
|
||||
callPackage,
|
||||
}:
|
||||
{
|
||||
interface,
|
||||
ppp-options,
|
||||
lcpEcho,
|
||||
username,
|
||||
password,
|
||||
debug
|
||||
debug,
|
||||
}:
|
||||
let
|
||||
name = "${interface.name}.pppoe";
|
||||
common = callPackage ./common.nix { inherit svc; };
|
||||
|
||||
timeoutOpt = if lcpEcho.interval != null then "-T ${builtins.toString (4 * lcpEcho.interval)}" else "";
|
||||
in common {
|
||||
inherit name debug username password lcpEcho ppp-options;
|
||||
timeoutOpt =
|
||||
if lcpEcho.interval != null then "-T ${builtins.toString (4 * lcpEcho.interval)}" else "";
|
||||
in
|
||||
common {
|
||||
inherit
|
||||
name
|
||||
debug
|
||||
username
|
||||
password
|
||||
lcpEcho
|
||||
ppp-options
|
||||
;
|
||||
command = ''
|
||||
exec ${ppp}/bin/pppd pty "${pppoe}/bin/pppoe ${timeoutOpt} -I $(output ${interface} ifname)" file /run/${name}/ppp-options
|
||||
'';
|
||||
|
@@ -1,8 +1,18 @@
|
||||
{ config, pkgs, lib, ... } :
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
svc = config.system.service;
|
||||
cfg = config.profile.gateway;
|
||||
inherit (lib) mkOption mkEnableOption mkIf types;
|
||||
inherit (lib)
|
||||
mkOption
|
||||
mkEnableOption
|
||||
mkIf
|
||||
types
|
||||
;
|
||||
inherit (pkgs) liminix serviceFns;
|
||||
inherit (liminix.services) bundle oneshot;
|
||||
hostaps =
|
||||
@@ -14,24 +24,27 @@ let
|
||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||
};
|
||||
in lib.mapAttrs'
|
||||
(name : value :
|
||||
let
|
||||
attrs = defaults // { ssid = name; } // value;
|
||||
in lib.nameValuePair
|
||||
"hostap-${name}"
|
||||
(svc.hostapd.build {
|
||||
interface = attrs.interface;
|
||||
params = lib.filterAttrs (k: v: k != "interface") attrs;
|
||||
}))
|
||||
cfg.wireless.networks;
|
||||
in {
|
||||
in
|
||||
lib.mapAttrs' (
|
||||
name: value:
|
||||
let
|
||||
attrs = defaults // { ssid = name; } // value;
|
||||
in
|
||||
lib.nameValuePair "hostap-${name}" (
|
||||
svc.hostapd.build {
|
||||
interface = attrs.interface;
|
||||
params = lib.filterAttrs (k: v: k != "interface") attrs;
|
||||
}
|
||||
)
|
||||
) cfg.wireless.networks;
|
||||
in
|
||||
{
|
||||
|
||||
options.profile.gateway = {
|
||||
lan = {
|
||||
interfaces = mkOption {
|
||||
type = types.listOf liminix.lib.types.interface;
|
||||
default = [];
|
||||
default = [ ];
|
||||
};
|
||||
address = mkOption {
|
||||
type = types.attrs;
|
||||
@@ -49,7 +62,7 @@ in {
|
||||
enable = mkEnableOption "firewall";
|
||||
rules = mkOption { type = types.attrsOf types.attrs; };
|
||||
zones = mkOption {
|
||||
type = types.attrsOf (types.listOf liminix.lib.types.service);
|
||||
type = types.attrsOf (types.listOf liminix.lib.types.service);
|
||||
default = {
|
||||
lan = [ config.services.int ];
|
||||
wan = [ config.services.wan ];
|
||||
@@ -82,11 +95,14 @@ in {
|
||||
];
|
||||
|
||||
config = {
|
||||
services.int = svc.network.address.build ({
|
||||
interface = svc.bridge.primary.build { ifname = "int"; };
|
||||
} // cfg.lan.address);
|
||||
services.int = svc.network.address.build (
|
||||
{
|
||||
interface = svc.bridge.primary.build { ifname = "int"; };
|
||||
}
|
||||
// cfg.lan.address
|
||||
);
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = config.services.int;
|
||||
members = cfg.lan.interfaces;
|
||||
};
|
||||
@@ -113,12 +129,15 @@ in {
|
||||
})
|
||||
];
|
||||
};
|
||||
in mkIf cfg.wan.dhcp6.enable bundl;
|
||||
in
|
||||
mkIf cfg.wan.dhcp6.enable bundl;
|
||||
|
||||
services.dns =
|
||||
let interface = config.services.int;
|
||||
dcfg = cfg.lan.dhcp;
|
||||
in svc.dnsmasq.build {
|
||||
let
|
||||
interface = config.services.int;
|
||||
dcfg = cfg.lan.dhcp;
|
||||
in
|
||||
svc.dnsmasq.build {
|
||||
resolvconf = config.services.resolvconf;
|
||||
inherit interface;
|
||||
ranges = [
|
||||
@@ -147,11 +166,12 @@ in {
|
||||
interface = config.services.wan;
|
||||
};
|
||||
|
||||
services.firewall = mkIf cfg.firewall.enable
|
||||
(svc.firewall.build {
|
||||
services.firewall = mkIf cfg.firewall.enable (
|
||||
svc.firewall.build {
|
||||
extraRules = cfg.firewall.rules;
|
||||
inherit (cfg.firewall) zones;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
dependencies = [ config.services.wan ];
|
||||
@@ -166,11 +186,13 @@ in {
|
||||
};
|
||||
|
||||
filesystem =
|
||||
let inherit (pkgs.pseudofile) dir symlink;
|
||||
in dir {
|
||||
let
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
in
|
||||
dir {
|
||||
etc = dir {
|
||||
"resolv.conf" = symlink "${config.services.resolvconf}/.outputs/resolv.conf";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -3,9 +3,10 @@
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
}:
|
||||
let
|
||||
inherit (pkgs) liminix;
|
||||
inherit (lib) mkOption types ;
|
||||
inherit (lib) mkOption types;
|
||||
|
||||
inherit (pkgs.liminix.services) oneshot target;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
@@ -22,19 +23,22 @@
|
||||
wpa_pairwise = "TKIP CCMP"; # auth for wpa (may not need this?)
|
||||
rsn_pairwise = "CCMP"; # auth for wpa2
|
||||
};
|
||||
in lib.mapAttrs'
|
||||
(name : value :
|
||||
let
|
||||
attrs = defaults // { ssid = name; } // value;
|
||||
in lib.nameValuePair
|
||||
"hostap-${name}"
|
||||
(svc.hostapd.build {
|
||||
interface = attrs.interface;
|
||||
params = lib.filterAttrs (k: v: k != "interface") attrs;
|
||||
}))
|
||||
cfg.wireless.networks;
|
||||
in
|
||||
lib.mapAttrs' (
|
||||
name: value:
|
||||
let
|
||||
attrs = defaults // { ssid = name; } // value;
|
||||
in
|
||||
lib.nameValuePair "hostap-${name}" (
|
||||
svc.hostapd.build {
|
||||
interface = attrs.interface;
|
||||
params = lib.filterAttrs (k: v: k != "interface") attrs;
|
||||
}
|
||||
)
|
||||
) cfg.wireless.networks;
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
../wlan.nix
|
||||
../network
|
||||
@@ -46,7 +50,7 @@ in {
|
||||
options.profile.wap = {
|
||||
interfaces = mkOption {
|
||||
type = types.listOf liminix.lib.types.interface;
|
||||
default = [];
|
||||
default = [ ];
|
||||
};
|
||||
wireless = mkOption {
|
||||
type = types.attrsOf types.anything;
|
||||
@@ -71,7 +75,7 @@ in {
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${config.services.dhcpc} router)";
|
||||
target = "default";
|
||||
dependencies = [config.services.dhcpc];
|
||||
dependencies = [ config.services.dhcpc ];
|
||||
};
|
||||
|
||||
services.resolvconf = oneshot rec {
|
||||
|
@@ -1,7 +1,8 @@
|
||||
{ config, lib, ... }:
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption; # types concatStringsSep;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
boot = {
|
||||
ramdisk = {
|
||||
|
@@ -3,13 +3,18 @@
|
||||
## Given a list of services, run each in turn until it exits, then
|
||||
## runs the next.
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
inherit (pkgs.liminix.services) longrun;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
system.service.round-robin = mkOption {
|
||||
description = "run services one at a time and failover to next";
|
||||
@@ -18,9 +23,9 @@ in {
|
||||
};
|
||||
config.system.service.round-robin = config.system.callService ./service.nix {
|
||||
services = mkOption {
|
||||
type = types.listOf liminix.lib.types.service;
|
||||
type = types.listOf liminix.lib.types.service;
|
||||
};
|
||||
name = mkOption {
|
||||
name = mkOption {
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
|
@@ -1,22 +1,30 @@
|
||||
{
|
||||
liminix, lib, s6-rc-round-robin
|
||||
liminix,
|
||||
lib,
|
||||
s6-rc-round-robin,
|
||||
}:
|
||||
{ services, name} :
|
||||
{ services, name }:
|
||||
let
|
||||
inherit (liminix.services) oneshot longrun;
|
||||
controlled-services = builtins.map
|
||||
(s: s.overrideAttrs(o: { inherit controller; }))
|
||||
services;
|
||||
controller = let name' = "control-${name}"; in longrun {
|
||||
name = name';
|
||||
run = ''
|
||||
in_outputs ${name'}
|
||||
exec ${s6-rc-round-robin}/bin/s6-rc-round-robin \
|
||||
-p ${proxy.name} \
|
||||
${lib.concatStringsSep " "
|
||||
(builtins.map (f: f.name) controlled-services)}
|
||||
'';
|
||||
};
|
||||
inherit (liminix.services) oneshot longrun;
|
||||
controlled-services = builtins.map (
|
||||
s:
|
||||
s.overrideAttrs (o: {
|
||||
inherit controller;
|
||||
})
|
||||
) services;
|
||||
controller =
|
||||
let
|
||||
name' = "control-${name}";
|
||||
in
|
||||
longrun {
|
||||
name = name';
|
||||
run = ''
|
||||
in_outputs ${name'}
|
||||
exec ${s6-rc-round-robin}/bin/s6-rc-round-robin \
|
||||
-p ${proxy.name} \
|
||||
${lib.concatStringsSep " " (builtins.map (f: f.name) controlled-services)}
|
||||
'';
|
||||
};
|
||||
proxy = oneshot rec {
|
||||
inherit name;
|
||||
inherit controller;
|
||||
@@ -29,4 +37,5 @@ let
|
||||
)
|
||||
'';
|
||||
};
|
||||
in proxy
|
||||
in
|
||||
proxy
|
||||
|
@@ -1,27 +1,39 @@
|
||||
{ config, pkgs, lib, lim, ... }:
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
lim,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (pkgs)
|
||||
execline
|
||||
s6
|
||||
s6-init-bin
|
||||
s6-linux-init
|
||||
stdenvNoCC;
|
||||
stdenvNoCC
|
||||
;
|
||||
inherit (lib.lists) unique concatMap;
|
||||
inherit (lib) concatStrings;
|
||||
inherit (builtins) map;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs.liminix.services) oneshot bundle longrun;
|
||||
inherit (lib) mkIf mkEnableOption mkOption types;
|
||||
inherit (lib)
|
||||
mkIf
|
||||
mkEnableOption
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
cfg = config.logging;
|
||||
|
||||
logger =
|
||||
let pipecmds =
|
||||
["${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1"] ++
|
||||
(lib.optional (cfg ? persistent && cfg.persistent.enable)
|
||||
"/bin/tee /dev/pmsg0") ++
|
||||
(lib.optional cfg.shipping.enable
|
||||
"${pkgs.logshipper}/bin/logtap ${cfg.shipping.socket} logshipper-socket-event");
|
||||
in ''
|
||||
let
|
||||
pipecmds =
|
||||
[ "${s6}/bin/s6-log -bpd3 -- ${cfg.script} 1" ]
|
||||
++ (lib.optional (cfg ? persistent && cfg.persistent.enable) "/bin/tee /dev/pmsg0")
|
||||
++ (lib.optional cfg.shipping.enable "${pkgs.logshipper}/bin/logtap ${cfg.shipping.socket} logshipper-socket-event");
|
||||
in
|
||||
''
|
||||
#!${execline}/bin/execlineb -P
|
||||
${execline}/bin/redirfd -w 1 /dev/null
|
||||
${execline}/bin/redirfd -rnb 0 fifo
|
||||
@@ -40,14 +52,12 @@ let
|
||||
# services and all services that have a controlled service as
|
||||
# dependency
|
||||
|
||||
isControlled = s : s ? controller && s.controller != null;
|
||||
deps = s : s.dependencies ++
|
||||
lib.optional (isControlled s) s.controller;
|
||||
flatDeps = s : [s] ++ concatMap flatDeps (deps s);
|
||||
isControlled = s: s ? controller && s.controller != null;
|
||||
deps = s: s.dependencies ++ lib.optional (isControlled s) s.controller;
|
||||
flatDeps = s: [ s ] ++ concatMap flatDeps (deps s);
|
||||
allServices = unique (concatMap flatDeps (builtins.attrValues config.services));
|
||||
isDependentOnControlled = s :
|
||||
isControlled s ||
|
||||
(lib.lists.any isDependentOnControlled s.dependencies);
|
||||
isDependentOnControlled =
|
||||
s: isControlled s || (lib.lists.any isDependentOnControlled s.dependencies);
|
||||
|
||||
# all controlled services depend on this oneshot, which
|
||||
# makes a list of them so we can identify them at runtime
|
||||
@@ -62,42 +72,45 @@ let
|
||||
down = "rm -r /run/services/controlled";
|
||||
};
|
||||
|
||||
defaultStart =
|
||||
builtins.filter
|
||||
(s: !(isDependentOnControlled s)) allServices;
|
||||
defaultStart = builtins.filter (s: !(isDependentOnControlled s)) allServices;
|
||||
defaultDefaultTarget = bundle {
|
||||
name = "default";
|
||||
contents = defaultStart ++ [controlled];
|
||||
contents = defaultStart ++ [ controlled ];
|
||||
};
|
||||
servicesAttrs = {
|
||||
default = defaultDefaultTarget;
|
||||
} // config.services;
|
||||
in
|
||||
pkgs.s6-rc-database.override {
|
||||
services = builtins.attrValues servicesAttrs;
|
||||
};
|
||||
pkgs.s6-rc-database.override {
|
||||
services = builtins.attrValues servicesAttrs;
|
||||
};
|
||||
s6-init-scripts = stdenvNoCC.mkDerivation {
|
||||
name = "s6-scripts";
|
||||
src = ./scripts;
|
||||
phases = ["unpackPhase" "installPhase" ];
|
||||
buildInputs = [];
|
||||
phases = [
|
||||
"unpackPhase"
|
||||
"installPhase"
|
||||
];
|
||||
buildInputs = [ ];
|
||||
installPhase = ''
|
||||
mkdir $out
|
||||
cp -r $src $out/scripts
|
||||
chmod -R +w $out
|
||||
'';
|
||||
};
|
||||
service = dir {
|
||||
service = dir {
|
||||
s6-linux-init-runleveld = dir {
|
||||
notification-fd = { file = "3"; };
|
||||
notification-fd = {
|
||||
file = "3";
|
||||
};
|
||||
run = {
|
||||
file = ''
|
||||
#!${execline}/bin/execlineb -P
|
||||
${execline}/bin/fdmove -c 2 1
|
||||
${execline}/bin/fdmove 1 3
|
||||
${s6}/bin/s6-ipcserver -1 -a 0700 -c 1 -- s
|
||||
${s6}/bin/s6-sudod -dt30000 -- "/etc/s6-linux-init/current"/scripts/runlevel
|
||||
'';
|
||||
#!${execline}/bin/execlineb -P
|
||||
${execline}/bin/fdmove -c 2 1
|
||||
${execline}/bin/fdmove 1 3
|
||||
${s6}/bin/s6-ipcserver -1 -a 0700 -c 1 -- s
|
||||
${s6}/bin/s6-sudod -dt30000 -- "/etc/s6-linux-init/current"/scripts/runlevel
|
||||
'';
|
||||
mode = "0755";
|
||||
};
|
||||
};
|
||||
@@ -108,12 +121,12 @@ let
|
||||
};
|
||||
run = {
|
||||
file = ''
|
||||
#!${execline}/bin/execlineb -P
|
||||
importas PATH PATH
|
||||
export PATH ${s6}/bin:''${PATH}
|
||||
foreground { echo path is ''${PATH} }
|
||||
${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
|
||||
'';
|
||||
#!${execline}/bin/execlineb -P
|
||||
importas PATH PATH
|
||||
export PATH ${s6}/bin:''${PATH}
|
||||
foreground { echo path is ''${PATH} }
|
||||
${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
|
||||
'';
|
||||
mode = "0755";
|
||||
};
|
||||
};
|
||||
@@ -122,8 +135,13 @@ let
|
||||
type = "i";
|
||||
mode = "0600";
|
||||
};
|
||||
notification-fd = { file = "3"; };
|
||||
run = { file = logger; mode = "0755"; };
|
||||
notification-fd = {
|
||||
file = "3";
|
||||
};
|
||||
run = {
|
||||
file = logger;
|
||||
mode = "0755";
|
||||
};
|
||||
};
|
||||
getty = dir {
|
||||
run = {
|
||||
@@ -166,7 +184,8 @@ let
|
||||
${s6-linux-init}/bin/s6-linux-init-shutdown -a #{action} -- now
|
||||
'';
|
||||
empty = "#!${execline}/bin/execlineb -P\n";
|
||||
in dir {
|
||||
in
|
||||
dir {
|
||||
crash = {
|
||||
file = quit "s6-svscan crashed. Rebooting.";
|
||||
mode = "0755";
|
||||
@@ -212,13 +231,15 @@ let
|
||||
|
||||
};
|
||||
};
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
logging = {
|
||||
shipping = {
|
||||
enable = mkEnableOption "unix socket for log shipping";
|
||||
socket = mkOption {
|
||||
description = "socket pathname"; type = types.path;
|
||||
description = "socket pathname";
|
||||
type = types.path;
|
||||
default = "/run/.log-shipping.sock";
|
||||
};
|
||||
service = mkOption {
|
||||
@@ -239,31 +260,46 @@ in {
|
||||
};
|
||||
};
|
||||
imports = [
|
||||
( {config, pkgs, lib, ...}:
|
||||
(
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.logging;
|
||||
pipeline = shipper: bundle {
|
||||
name = "log-shipping-pipe";
|
||||
contents = let
|
||||
eat = longrun {
|
||||
name = "log-shipping-pipe-eat";
|
||||
run = ''
|
||||
fdmove -c 12 1 \
|
||||
${pkgs.s6}/bin/s6-ipcserver ${cfg.shipping.socket} \
|
||||
fdmove -c 1 12 \
|
||||
cat
|
||||
'';
|
||||
producer-for = spew.name;
|
||||
};
|
||||
spew = shipper.override {
|
||||
consumer-for ="log-shipping-pipe-eat";
|
||||
};
|
||||
in [ eat spew ];
|
||||
};
|
||||
in mkIf cfg.shipping.enable {
|
||||
pipeline =
|
||||
shipper:
|
||||
bundle {
|
||||
name = "log-shipping-pipe";
|
||||
contents =
|
||||
let
|
||||
eat = longrun {
|
||||
name = "log-shipping-pipe-eat";
|
||||
run = ''
|
||||
fdmove -c 12 1 \
|
||||
${pkgs.s6}/bin/s6-ipcserver ${cfg.shipping.socket} \
|
||||
fdmove -c 1 12 \
|
||||
cat
|
||||
'';
|
||||
producer-for = spew.name;
|
||||
};
|
||||
spew = shipper.override {
|
||||
consumer-for = "log-shipping-pipe-eat";
|
||||
};
|
||||
in
|
||||
[
|
||||
eat
|
||||
spew
|
||||
];
|
||||
};
|
||||
in
|
||||
mkIf cfg.shipping.enable {
|
||||
services.${cfg.shipping.service.name} = pipeline cfg.shipping.service;
|
||||
}
|
||||
)];
|
||||
)
|
||||
];
|
||||
|
||||
config = {
|
||||
filesystem = dir {
|
||||
@@ -274,9 +310,11 @@ in {
|
||||
s6-linux-init = dir {
|
||||
current = dir {
|
||||
scripts = symlink "${s6-init-scripts}/scripts";
|
||||
env = dir {};
|
||||
env = dir { };
|
||||
run-image = dir {
|
||||
uncaught-logs = (dir {}) // {mode = "2750";};
|
||||
uncaught-logs = (dir { }) // {
|
||||
mode = "2750";
|
||||
};
|
||||
inherit service;
|
||||
};
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ config, pkgs, ... } :
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
config = {
|
||||
programs.busybox = {
|
||||
@@ -14,6 +14,6 @@
|
||||
FEATURE_FANCY_ECHO = "y";
|
||||
};
|
||||
};
|
||||
defaultProfile.packages = [ pkgs.schnapps ] ;
|
||||
defaultProfile.packages = [ pkgs.schnapps ];
|
||||
};
|
||||
}
|
||||
|
@@ -3,12 +3,18 @@
|
||||
## various ways to manage secrets without writing them to the
|
||||
## nix store
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
inherit (pkgs.liminix.services) longrun;
|
||||
in {
|
||||
in
|
||||
{
|
||||
options.system.service.secrets = {
|
||||
outboard = mkOption {
|
||||
description = "fetch secrets from external vault with https";
|
||||
@@ -42,7 +48,7 @@ in {
|
||||
description = "service name";
|
||||
type = types.str;
|
||||
};
|
||||
interval = mkOption {
|
||||
interval = mkOption {
|
||||
type = types.int;
|
||||
default = 30;
|
||||
description = "how often to check the source, in minutes";
|
||||
@@ -57,7 +63,7 @@ in {
|
||||
description = "service name";
|
||||
type = types.str;
|
||||
};
|
||||
interval = mkOption {
|
||||
interval = mkOption {
|
||||
type = types.int;
|
||||
default = 30;
|
||||
description = "how often to check the source, in minutes";
|
||||
@@ -76,9 +82,16 @@ in {
|
||||
description = "how do we notify the service to regenerate its config";
|
||||
default = "restart-all";
|
||||
type = types.enum [
|
||||
"restart" "restart-all"
|
||||
"hup" "int" "quit" "kill" "term"
|
||||
"winch" "usr1" "usr2"
|
||||
"restart"
|
||||
"restart-all"
|
||||
"hup"
|
||||
"int"
|
||||
"quit"
|
||||
"kill"
|
||||
"term"
|
||||
"winch"
|
||||
"usr1"
|
||||
"usr2"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
@@ -1,11 +1,21 @@
|
||||
{
|
||||
liminix, lib, json-to-fstree, serviceFns
|
||||
liminix,
|
||||
lib,
|
||||
json-to-fstree,
|
||||
serviceFns,
|
||||
}:
|
||||
{
|
||||
name,
|
||||
url,
|
||||
interval,
|
||||
username,
|
||||
password,
|
||||
}:
|
||||
{ name, url, interval, username, password } :
|
||||
let
|
||||
inherit (liminix.services) oneshot longrun;
|
||||
inherit (lib) optionalString;
|
||||
in longrun {
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
buildInputs = [ json-to-fstree ];
|
||||
run = ''
|
||||
|
@@ -1,7 +1,16 @@
|
||||
{
|
||||
liminix, lib, lim, s6, s6-rc, watch-outputs
|
||||
liminix,
|
||||
lib,
|
||||
lim,
|
||||
s6,
|
||||
s6-rc,
|
||||
watch-outputs,
|
||||
}:
|
||||
{
|
||||
watch,
|
||||
service,
|
||||
action,
|
||||
}:
|
||||
{ watch, service, action } :
|
||||
let
|
||||
inherit (liminix.services) oneshot longrun;
|
||||
inherit (builtins) length head toString;
|
||||
@@ -11,41 +20,51 @@ let
|
||||
watched-services = unique (map (f: f "service") watch);
|
||||
paths = unique (map (f: f "path") watch);
|
||||
|
||||
restart-flag = {
|
||||
restart = "-r";
|
||||
restart-all = "-R";
|
||||
"hup" = "-s 1";
|
||||
"int" = "-s 2";
|
||||
"quit" = "-s 3";
|
||||
"kill" = "-s 9";
|
||||
"term" = "-s 15";
|
||||
"winch" = "-s 28";
|
||||
"usr1" = "-s 10";
|
||||
"usr2" = "-s 12";
|
||||
}.${action};
|
||||
restart-flag =
|
||||
{
|
||||
restart = "-r";
|
||||
restart-all = "-R";
|
||||
"hup" = "-s 1";
|
||||
"int" = "-s 2";
|
||||
"quit" = "-s 3";
|
||||
"kill" = "-s 9";
|
||||
"term" = "-s 15";
|
||||
"winch" = "-s 28";
|
||||
"usr1" = "-s 10";
|
||||
"usr2" = "-s 12";
|
||||
}
|
||||
.${action};
|
||||
|
||||
watched-service =
|
||||
if length watched-services == 0
|
||||
then null
|
||||
else if length watched-services == 1
|
||||
then head watched-services
|
||||
else throw "cannot subscribe to more than one source service for secrets";
|
||||
if length watched-services == 0 then
|
||||
null
|
||||
else if length watched-services == 1 then
|
||||
head watched-services
|
||||
else
|
||||
throw "cannot subscribe to more than one source service for secrets";
|
||||
|
||||
watcher = let name' = "restart-${name}"; in longrun {
|
||||
name = name';
|
||||
run = ''
|
||||
dir=/run/service/${name}
|
||||
echo waiting for $dir
|
||||
if test -e $dir/notification-fd; then flag="-U"; else flag="-u"; fi
|
||||
${s6}/bin/s6-svwait $flag /run/service/${name} || exit
|
||||
PATH=${s6-rc}/bin:${s6}/bin:$PATH
|
||||
${watch-outputs}/bin/watch-outputs ${restart-flag} ${name} ${watched-service.name} ${lib.concatStringsSep " " paths}
|
||||
'';
|
||||
};
|
||||
in service.overrideAttrs(o: {
|
||||
buildInputs = (lim.orEmpty o.buildInputs) ++
|
||||
optional (watched-service != null) watcher;
|
||||
dependencies = (lim.orEmpty o.dependencies) ++
|
||||
optionals (watched-service != null)
|
||||
[ watcher watched-service ];
|
||||
watcher =
|
||||
let
|
||||
name' = "restart-${name}";
|
||||
in
|
||||
longrun {
|
||||
name = name';
|
||||
run = ''
|
||||
dir=/run/service/${name}
|
||||
echo waiting for $dir
|
||||
if test -e $dir/notification-fd; then flag="-U"; else flag="-u"; fi
|
||||
${s6}/bin/s6-svwait $flag /run/service/${name} || exit
|
||||
PATH=${s6-rc}/bin:${s6}/bin:$PATH
|
||||
${watch-outputs}/bin/watch-outputs ${restart-flag} ${name} ${watched-service.name} ${lib.concatStringsSep " " paths}
|
||||
'';
|
||||
};
|
||||
in
|
||||
service.overrideAttrs (o: {
|
||||
buildInputs = (lim.orEmpty o.buildInputs) ++ optional (watched-service != null) watcher;
|
||||
dependencies =
|
||||
(lim.orEmpty o.dependencies)
|
||||
++ optionals (watched-service != null) [
|
||||
watcher
|
||||
watched-service
|
||||
];
|
||||
})
|
||||
|
@@ -1,11 +1,20 @@
|
||||
{
|
||||
liminix, lib, json-to-fstree, serviceFns, tangc
|
||||
liminix,
|
||||
lib,
|
||||
json-to-fstree,
|
||||
serviceFns,
|
||||
tangc,
|
||||
}:
|
||||
{
|
||||
name,
|
||||
path,
|
||||
interval,
|
||||
}:
|
||||
{ name, path, interval } :
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib) optionalString;
|
||||
in longrun {
|
||||
in
|
||||
longrun {
|
||||
inherit name;
|
||||
buildInputs = [ json-to-fstree ];
|
||||
notification-fd = 10;
|
||||
|
@@ -3,18 +3,26 @@
|
||||
##
|
||||
## Provide SSH service using Dropbear
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
inherit (pkgs.pseudofile) dir file;
|
||||
mkBoolOption = description : mkOption {
|
||||
type = types.bool;
|
||||
inherit description;
|
||||
default = true;
|
||||
};
|
||||
mkBoolOption =
|
||||
description:
|
||||
mkOption {
|
||||
type = types.bool;
|
||||
inherit description;
|
||||
default = true;
|
||||
};
|
||||
|
||||
in {
|
||||
in
|
||||
{
|
||||
options = {
|
||||
system.service.ssh = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
@@ -47,15 +55,16 @@ in {
|
||||
allowLocalPortForward = mkBoolOption "Enable local port forwarding";
|
||||
allowRemotePortForward = mkBoolOption "Enable remote port forwarding";
|
||||
allowRemoteConnectionToForwardedPorts = mkOption {
|
||||
type = types.bool; default = false;
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Allow remote hosts to connect to local forwarded ports (by default they are bound to loopback)";
|
||||
};
|
||||
authorizedKeys = mkOption {
|
||||
type = types.nullOr (liminix.lib.types.replacable (types.attrsOf (types.listOf types.nonEmptyStr)));
|
||||
example = {
|
||||
root = ["ssh-rsa AAAAB3N...aZaZ"];
|
||||
alice = ["ssh-rsa AAAAB3N...qS4r"];
|
||||
bob = [];
|
||||
root = [ "ssh-rsa AAAAB3N...aZaZ" ];
|
||||
alice = [ "ssh-rsa AAAAB3N...qS4r" ];
|
||||
bob = [ ];
|
||||
};
|
||||
default = null;
|
||||
description = "Authorized SSH public keys for each username. If this optin is provided it overrides any keys found in /home/{username}/.ssh";
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
liminix
|
||||
, dropbear
|
||||
, lib
|
||||
, watch-ssh-keys
|
||||
liminix,
|
||||
dropbear,
|
||||
lib,
|
||||
watch-ssh-keys,
|
||||
}:
|
||||
{
|
||||
address,
|
||||
@@ -14,7 +14,7 @@
|
||||
allowRoot,
|
||||
authorizedKeys,
|
||||
port,
|
||||
extraConfig
|
||||
extraConfig,
|
||||
}:
|
||||
let
|
||||
name = "sshd";
|
||||
@@ -24,37 +24,39 @@ let
|
||||
keydir = "/run/${name}/authorized_keys";
|
||||
options =
|
||||
[
|
||||
"-e" # pass environment to child
|
||||
"-E" # log to stderr
|
||||
"-R" # create hostkeys if needed
|
||||
"-e" # pass environment to child
|
||||
"-E" # log to stderr
|
||||
"-R" # create hostkeys if needed
|
||||
"-P /run/dropbear.pid"
|
||||
"-F" # don't fork into background
|
||||
] ++
|
||||
(lib.optional (! allowRoot) "-w") ++
|
||||
(lib.optional (! allowPasswordLogin) "-s") ++
|
||||
(lib.optional (! allowPasswordLoginForRoot) "-g") ++
|
||||
(lib.optional (! allowLocalPortForward) "-j") ++
|
||||
(lib.optional (! allowRemotePortForward) "-k") ++
|
||||
(lib.optional (! allowRemoteConnectionToForwardedPorts) "-a") ++
|
||||
(lib.optionals (authorizedKeys != null) ["-U" "${keydir}/%n"]) ++
|
||||
[(if address != null
|
||||
then "-p ${address}:${toString port}"
|
||||
else "-p ${toString port}")] ++
|
||||
[extraConfig];
|
||||
"-F" # don't fork into background
|
||||
]
|
||||
++ (lib.optional (!allowRoot) "-w")
|
||||
++ (lib.optional (!allowPasswordLogin) "-s")
|
||||
++ (lib.optional (!allowPasswordLoginForRoot) "-g")
|
||||
++ (lib.optional (!allowLocalPortForward) "-j")
|
||||
++ (lib.optional (!allowRemotePortForward) "-k")
|
||||
++ (lib.optional (!allowRemoteConnectionToForwardedPorts) "-a")
|
||||
++ (lib.optionals (authorizedKeys != null) [
|
||||
"-U"
|
||||
"${keydir}/%n"
|
||||
])
|
||||
++ [
|
||||
(if address != null then "-p ${address}:${toString port}" else "-p ${toString port}")
|
||||
]
|
||||
++ [ extraConfig ];
|
||||
isKeyservice = typeOf authorizedKeys == "lambda";
|
||||
authKeysConcat =
|
||||
if authorizedKeys != null && !isKeyservice
|
||||
then mapAttrs
|
||||
(n : v : concatStringsSep "\\n" v)
|
||||
authorizedKeys
|
||||
else {};
|
||||
if authorizedKeys != null && !isKeyservice then
|
||||
mapAttrs (n: v: concatStringsSep "\\n" v) authorizedKeys
|
||||
else
|
||||
{ };
|
||||
keyservice = longrun {
|
||||
name = "${name}-watch-keys";
|
||||
run = ''
|
||||
mkdir -p ${keydir}
|
||||
exec ${watch-ssh-keys}/bin/watch-ssh-keys -d ${keydir} ${authorizedKeys "service"} ${authorizedKeys "path"}
|
||||
'';
|
||||
dependencies = [ (authorizedKeys "service") ] ;
|
||||
dependencies = [ (authorizedKeys "service") ];
|
||||
};
|
||||
in
|
||||
longrun {
|
||||
@@ -66,12 +68,9 @@ longrun {
|
||||
run = ''
|
||||
ln -s $(mkstate dropbear) /run
|
||||
mkdir -p /run/${name}/authorized_keys
|
||||
${concatStringsSep "\n"
|
||||
(mapAttrsToList
|
||||
(n : v : "echo -e '${v}' > /run/${name}/authorized_keys/${n} ")
|
||||
authKeysConcat
|
||||
)
|
||||
}
|
||||
${concatStringsSep "\n" (
|
||||
mapAttrsToList (n: v: "echo -e '${v}' > /run/${name}/authorized_keys/${n} ") authKeysConcat
|
||||
)}
|
||||
. /etc/profile # sets PATH but do we need this? it's the same file as ashrc
|
||||
exec env -i ENV=/etc/ashrc PATH=$PATH ${dropbear}/bin/dropbear ${concatStringsSep " " options}
|
||||
'';
|
||||
|
@@ -1,9 +1,16 @@
|
||||
{ liminix, certifix-client, svc, lib, writeText, serviceFns }:
|
||||
{
|
||||
liminix,
|
||||
certifix-client,
|
||||
svc,
|
||||
lib,
|
||||
writeText,
|
||||
serviceFns,
|
||||
}:
|
||||
{
|
||||
caCertificate,
|
||||
secret,
|
||||
subject,
|
||||
serviceUrl
|
||||
serviceUrl,
|
||||
}:
|
||||
let
|
||||
inherit (builtins) filter isString split;
|
||||
@@ -11,7 +18,8 @@ let
|
||||
name = "certifix-${lib.strings.sanitizeDerivationName subject}";
|
||||
caCertFile = writeText "ca.crt" caCertificate;
|
||||
secretFile = writeText "secret" secret;
|
||||
in oneshot {
|
||||
in
|
||||
oneshot {
|
||||
inherit name;
|
||||
up = ''
|
||||
(in_outputs ${name}
|
||||
|
@@ -1,5 +1,9 @@
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
@@ -7,34 +11,35 @@ in
|
||||
{
|
||||
options = {
|
||||
system.service.tls-certificate = {
|
||||
certifix-client = mkOption {
|
||||
certifix-client = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
};
|
||||
};
|
||||
config.system.service.tls-certificate.certifix-client =
|
||||
config.system.callService ./certifix-client.nix {
|
||||
# this is probably read from files on the build machine,
|
||||
# but are not named with ...File suffix because they are
|
||||
# not files on the device (they get embedded into the store)
|
||||
caCertificate = mkOption {
|
||||
description = "CA certificate in PEM format. This must be the same CA as that which signed the certificate of the Certifix server";
|
||||
type = types.str;
|
||||
config.system.callService ./certifix-client.nix
|
||||
{
|
||||
# this is probably read from files on the build machine,
|
||||
# but are not named with ...File suffix because they are
|
||||
# not files on the device (they get embedded into the store)
|
||||
caCertificate = mkOption {
|
||||
description = "CA certificate in PEM format. This must be the same CA as that which signed the certificate of the Certifix server";
|
||||
type = types.str;
|
||||
};
|
||||
secret = mkOption {
|
||||
description = "The shared secret to embed in signing request. This must match the secret configured in the Certifix service, otherwise it will refuse to sign the CSR.";
|
||||
type = types.str;
|
||||
};
|
||||
subject = mkOption {
|
||||
description = "Subject of the certificate request, as an X509 DN. The CN ('Common Name') you provide here is also used as the value of the SubjectAlternativeName extension.";
|
||||
type = types.str;
|
||||
example = "C=GB,ST=London,O=Liminix,OU=IT,CN=myhostname";
|
||||
};
|
||||
serviceUrl = mkOption {
|
||||
description = "Certifix server endpoint URL";
|
||||
type = types.str;
|
||||
example = "https://certifix.lan:19613/sign";
|
||||
};
|
||||
};
|
||||
secret = mkOption {
|
||||
description = "The shared secret to embed in signing request. This must match the secret configured in the Certifix service, otherwise it will refuse to sign the CSR.";
|
||||
type = types.str;
|
||||
};
|
||||
subject = mkOption {
|
||||
description = "Subject of the certificate request, as an X509 DN. The CN ('Common Name') you provide here is also used as the value of the SubjectAlternativeName extension.";
|
||||
type = types.str;
|
||||
example = "C=GB,ST=London,O=Liminix,OU=IT,CN=myhostname";
|
||||
};
|
||||
serviceUrl = mkOption {
|
||||
description = "Certifix server endpoint URL";
|
||||
type = types.str;
|
||||
example = "https://certifix.lan:19613/sign";
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -1,12 +1,18 @@
|
||||
# this is unlikely to be the final form or location of this code, it's
|
||||
# an interim module which wraps the uevent-watch command
|
||||
|
||||
{ lib, pkgs, config, ... }:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
in
|
||||
# inherit (pkgs.liminix.services) bundle;
|
||||
in {
|
||||
{
|
||||
options = {
|
||||
system.service.uevent-rule = mkOption {
|
||||
description = "a service which starts other services based on device state (sysfs)";
|
||||
@@ -25,7 +31,7 @@ in {
|
||||
devtype = "usb_device";
|
||||
attrs.idVendor = "8086";
|
||||
};
|
||||
default = {};
|
||||
default = { };
|
||||
};
|
||||
symlink = mkOption {
|
||||
description = "create symlink targeted on devpath";
|
||||
|
@@ -1,23 +1,30 @@
|
||||
{
|
||||
liminix
|
||||
, uevent-watch
|
||||
, lib }:
|
||||
liminix,
|
||||
uevent-watch,
|
||||
lib,
|
||||
}:
|
||||
{
|
||||
serviceName, terms, symlink
|
||||
serviceName,
|
||||
terms,
|
||||
symlink,
|
||||
}:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
inherit (lib.attrsets) collect mapAttrsRecursive;
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
stringify = attrs :
|
||||
concatStringsSep " "
|
||||
(collect lib.isString
|
||||
(mapAttrsRecursive
|
||||
(path : value : "${concatStringsSep "." path}=${value}")
|
||||
attrs));
|
||||
stringify =
|
||||
attrs:
|
||||
concatStringsSep " " (
|
||||
collect lib.isString (
|
||||
mapAttrsRecursive (path: value: "${concatStringsSep "." path}=${value}") attrs
|
||||
)
|
||||
);
|
||||
termsString = stringify terms;
|
||||
in longrun {
|
||||
in
|
||||
longrun {
|
||||
name = "watch-for-${serviceName}";
|
||||
restart-on-upgrade = true;
|
||||
run = "${uevent-watch}/bin/uevent-watch ${if symlink != null then "-n ${symlink}" else ""} -s ${serviceName} ${termsString}";
|
||||
run = "${uevent-watch}/bin/uevent-watch ${
|
||||
if symlink != null then "-n ${symlink}" else ""
|
||||
} -s ${serviceName} ${termsString}";
|
||||
}
|
||||
|
@@ -10,11 +10,20 @@
|
||||
## the immutable store, so you can't e.g change a password with
|
||||
## :command:`passwd`
|
||||
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
concatStrings concatStringsSep mapAttrsToList mkOption types;
|
||||
concatStrings
|
||||
concatStringsSep
|
||||
mapAttrsToList
|
||||
mkOption
|
||||
types
|
||||
;
|
||||
inherit (builtins) toString;
|
||||
inherit (pkgs.pseudofile) dir;
|
||||
passwd-file =
|
||||
@@ -28,82 +37,98 @@ let
|
||||
in
|
||||
concatStrings lines;
|
||||
group-file =
|
||||
let lines = mapAttrsToList
|
||||
(name: {gid, usernames ? []}:
|
||||
"${name}:x:${toString gid}:${concatStringsSep "," usernames}\n" )
|
||||
config.groups;
|
||||
in concatStrings lines;
|
||||
in {
|
||||
let
|
||||
lines = mapAttrsToList (
|
||||
name:
|
||||
{
|
||||
gid,
|
||||
usernames ? [ ],
|
||||
}:
|
||||
"${name}:x:${toString gid}:${concatStringsSep "," usernames}\n"
|
||||
) config.groups;
|
||||
in
|
||||
concatStrings lines;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
users = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
passwd = mkOption {
|
||||
type = types.str;
|
||||
description = "encrypted password, as generated by mkpasswd -m sha512crypt";
|
||||
example = "$6$RIYL.EgWOrtoJ0/7$Z53a8sc0o6AU/kuFOGiLJKhwVavTG/deoM7JTs6luNczYSUsh4UYmhvT8sVzm.l8F/LZXhhhkC7IHQs5UGAIM/";
|
||||
default = "!!";
|
||||
users = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
passwd = mkOption {
|
||||
type = types.str;
|
||||
description = "encrypted password, as generated by mkpasswd -m sha512crypt";
|
||||
example = "$6$RIYL.EgWOrtoJ0/7$Z53a8sc0o6AU/kuFOGiLJKhwVavTG/deoM7JTs6luNczYSUsh4UYmhvT8sVzm.l8F/LZXhhhkC7IHQs5UGAIM/";
|
||||
default = "!!";
|
||||
};
|
||||
uid = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
gid = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
gecos = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "Jo Q User";
|
||||
};
|
||||
dir = mkOption {
|
||||
type = types.str;
|
||||
default = "/run";
|
||||
};
|
||||
shell = mkOption {
|
||||
type = types.str;
|
||||
default = "/bin/sh";
|
||||
};
|
||||
openssh.authorizedKeys.keys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
uid = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
gid = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
gecos = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "Jo Q User";
|
||||
};
|
||||
dir = mkOption {
|
||||
type = types.str;
|
||||
default = "/run";
|
||||
};
|
||||
shell = mkOption {
|
||||
type = types.str;
|
||||
default = "/bin/sh";
|
||||
};
|
||||
openssh.authorizedKeys.keys = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
groups = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
gid = mkOption {
|
||||
type = types.int;
|
||||
groups = mkOption {
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
gid = mkOption {
|
||||
type = types.int;
|
||||
};
|
||||
usernames = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
usernames = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
config =
|
||||
let authorized_key_files =
|
||||
lib.attrsets.mapAttrs
|
||||
(name: val: dir {
|
||||
".ssh" = dir {
|
||||
authorized_keys = {
|
||||
inherit (val) uid gid;
|
||||
type = "f";
|
||||
mode = "0400";
|
||||
file = lib.concatStringsSep
|
||||
"\n" val.openssh.authorizedKeys.keys;
|
||||
};
|
||||
};
|
||||
})
|
||||
config.users;
|
||||
in {
|
||||
let
|
||||
authorized_key_files = lib.attrsets.mapAttrs (
|
||||
name: val:
|
||||
dir {
|
||||
".ssh" = dir {
|
||||
authorized_keys = {
|
||||
inherit (val) uid gid;
|
||||
type = "f";
|
||||
mode = "0400";
|
||||
file = lib.concatStringsSep "\n" val.openssh.authorizedKeys.keys;
|
||||
};
|
||||
};
|
||||
}
|
||||
) config.users;
|
||||
in
|
||||
{
|
||||
filesystem = dir {
|
||||
etc = dir {
|
||||
passwd = { file = passwd-file; };
|
||||
group = { file = group-file; };
|
||||
passwd = {
|
||||
file = passwd-file;
|
||||
};
|
||||
group = {
|
||||
file = group-file;
|
||||
};
|
||||
};
|
||||
home = dir authorized_key_files;
|
||||
};
|
||||
|
@@ -10,7 +10,12 @@
|
||||
## and require using VLAN in order to send different traffic to
|
||||
## different ports (e.g. LAN vs WAN)
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
|
@@ -1,11 +1,16 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
liminix,
|
||||
lib,
|
||||
}:
|
||||
{
|
||||
ifname,
|
||||
primary,
|
||||
vid,
|
||||
}:
|
||||
{ ifname, primary, vid } :
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
in oneshot rec {
|
||||
in
|
||||
oneshot rec {
|
||||
name = "${ifname}.link";
|
||||
up = ''
|
||||
ip link add link $(output ${primary} ifname) name ${ifname} type vlan id ${vid}
|
||||
|
@@ -4,14 +4,19 @@
|
||||
## feed it by checking the health of specified critical services.
|
||||
## If the watchdog feeder stops, the device will reboot.
|
||||
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
system.service.watchdog = mkOption {
|
||||
system.service.watchdog = mkOption {
|
||||
type = liminix.lib.types.serviceDefn;
|
||||
};
|
||||
};
|
||||
|
@@ -1,13 +1,15 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, s6
|
||||
liminix,
|
||||
lib,
|
||||
s6,
|
||||
}:
|
||||
{ watched, headStart } :
|
||||
{ watched, headStart }:
|
||||
let
|
||||
inherit (liminix.services) longrun;
|
||||
in longrun {
|
||||
in
|
||||
longrun {
|
||||
name = "watchdog";
|
||||
run =
|
||||
"PATH=${s6}/bin:$PATH HEADSTART=${toString headStart} ${./gaspode.sh} ${lib.concatStringsSep " " (builtins.map (s: s.name) watched)}";
|
||||
run = "PATH=${s6}/bin:$PATH HEADSTART=${toString headStart} ${./gaspode.sh} ${
|
||||
lib.concatStringsSep " " (builtins.map (s: s.name) watched)
|
||||
}";
|
||||
}
|
||||
|
@@ -1,4 +1,9 @@
|
||||
{ lib, pkgs, config, ...}:
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs) stdenv wireless-regdb;
|
||||
@@ -10,7 +15,8 @@ let
|
||||
cp ${wireless-regdb}/lib/firmware/regulatory.db $out/
|
||||
'';
|
||||
};
|
||||
in {
|
||||
in
|
||||
{
|
||||
config = {
|
||||
filesystem = dir {
|
||||
lib = dir {
|
||||
@@ -20,7 +26,8 @@ in {
|
||||
};
|
||||
};
|
||||
programs.busybox.applets = [
|
||||
"insmod" "rmmod"
|
||||
"insmod"
|
||||
"rmmod"
|
||||
];
|
||||
kernel = rec {
|
||||
config = {
|
||||
|
@@ -1,12 +1,18 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (pkgs) liminix;
|
||||
inherit (lib) mkOption types;
|
||||
huawei-cdc-ncm = pkgs.kmodloader.override {
|
||||
targets = ["huawei_cdc_ncm"];
|
||||
targets = [ "huawei_cdc_ncm" ];
|
||||
inherit (config.system.outputs) kernel;
|
||||
};
|
||||
in {
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
../uevent-rule
|
||||
../mdevd.nix
|
||||
@@ -25,25 +31,35 @@ in {
|
||||
USB_SERIAL_OPTION = "y";
|
||||
};
|
||||
programs.busybox.applets = [
|
||||
"insmod" "rmmod"
|
||||
"insmod"
|
||||
"rmmod"
|
||||
];
|
||||
|
||||
# https://www.0xf8.org/2017/01/flashing-a-huawei-e3372h-4g-lte-stick-from-hilink-to-stick-mode/
|
||||
system.service.wwan.huawei-e3372 =
|
||||
let svc = config.system.callService ./huawei-e3372.nix {
|
||||
apn = mkOption { type = types.str; };
|
||||
username = mkOption { type = types.str; };
|
||||
password = mkOption { type = types.str; };
|
||||
authType = mkOption { type = types.enum [ "pap" "chap" ]; };
|
||||
let
|
||||
svc = config.system.callService ./huawei-e3372.nix {
|
||||
apn = mkOption { type = types.str; };
|
||||
username = mkOption { type = types.str; };
|
||||
password = mkOption { type = types.str; };
|
||||
authType = mkOption {
|
||||
type = types.enum [
|
||||
"pap"
|
||||
"chap"
|
||||
];
|
||||
};
|
||||
in
|
||||
svc // {
|
||||
build = args :
|
||||
let args' = args // {
|
||||
dependencies = (args.dependencies or []) ++
|
||||
[huawei-cdc-ncm];
|
||||
};
|
||||
in svc.build args' ;
|
||||
};
|
||||
in
|
||||
svc
|
||||
// {
|
||||
build =
|
||||
args:
|
||||
let
|
||||
args' = args // {
|
||||
dependencies = (args.dependencies or [ ]) ++ [ huawei-cdc-ncm ];
|
||||
};
|
||||
in
|
||||
svc.build args';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,12 +1,17 @@
|
||||
{
|
||||
liminix
|
||||
, usb-modeswitch
|
||||
, ppp
|
||||
, lib
|
||||
, svc
|
||||
, uevent-watch
|
||||
liminix,
|
||||
usb-modeswitch,
|
||||
ppp,
|
||||
lib,
|
||||
svc,
|
||||
uevent-watch,
|
||||
}:
|
||||
{
|
||||
apn,
|
||||
username,
|
||||
password,
|
||||
authType,
|
||||
}:
|
||||
{ apn, username, password, authType }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
authTypeNum = if authType == "pap" then "1" else "2";
|
||||
@@ -16,25 +21,36 @@ let
|
||||
# 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"
|
||||
""
|
||||
"AT"
|
||||
"OK"
|
||||
"ATZ"
|
||||
# create PDP context
|
||||
"OK" "AT+CGDCONT=1,\"IP\",\"${apn}\""
|
||||
"OK"
|
||||
"AT+CGDCONT=1,\"IP\",\"${apn}\""
|
||||
# activate PDP context
|
||||
"OK" "AT+CGACT=1,1"
|
||||
"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}\""
|
||||
"OK"
|
||||
"AT\\^AUTHDATA=1,${authTypeNum},\"\",\"${password}\",\"${username}\""
|
||||
# start the thing (I am choosing to read this as "NDIS DialUP")
|
||||
"OK" "AT\\^NDISDUP=1,1"
|
||||
"OK"
|
||||
"AT\\^NDISDUP=1,1"
|
||||
"OK"
|
||||
];
|
||||
modeswitch = oneshot rec {
|
||||
name = "modem-modeswitch";
|
||||
controller = (svc.uevent-rule.build {
|
||||
serviceName = name;
|
||||
terms = { devtype = "usb_device"; product = "12d1/14fe/102"; };
|
||||
});
|
||||
controller = (
|
||||
svc.uevent-rule.build {
|
||||
serviceName = name;
|
||||
terms = {
|
||||
devtype = "usb_device";
|
||||
product = "12d1/14fe/102";
|
||||
};
|
||||
}
|
||||
);
|
||||
up = ''
|
||||
${usb-modeswitch}/bin/usb_modeswitch -v 12d1 -p 14fe --huawei-new-mode
|
||||
'';
|
||||
@@ -45,17 +61,19 @@ let
|
||||
# is only running when the stick is in the wrong mode
|
||||
dependencies = [ modeswitch.controller ];
|
||||
buildInputs = [ modeswitch ];
|
||||
controller = (svc.uevent-rule.build {
|
||||
serviceName = name;
|
||||
terms = {
|
||||
subsystem = "tty";
|
||||
attrs = {
|
||||
idVendor = "12d1";
|
||||
idProduct = "1506";
|
||||
controller = (
|
||||
svc.uevent-rule.build {
|
||||
serviceName = name;
|
||||
terms = {
|
||||
subsystem = "tty";
|
||||
attrs = {
|
||||
idVendor = "12d1";
|
||||
idProduct = "1506";
|
||||
};
|
||||
};
|
||||
};
|
||||
symlink = "/dev/modem";
|
||||
});
|
||||
symlink = "/dev/modem";
|
||||
}
|
||||
);
|
||||
up = ''
|
||||
ls -l /dev/modem
|
||||
test -L /dev/modem || exit 1
|
||||
@@ -64,7 +82,8 @@ let
|
||||
down = "${ppp}/bin/chat -v '' ATZ OK 0<>/dev/modem 1>&0";
|
||||
};
|
||||
|
||||
in svc.network.link.build {
|
||||
in
|
||||
svc.network.link.build {
|
||||
ifname = "wwan0";
|
||||
dependencies = [ atz ];
|
||||
}
|
||||
|
@@ -10,7 +10,12 @@
|
||||
## failure on the primary partition. The exact details are specifics to your device.
|
||||
## See the Zyxel NWA50AX for an example.
|
||||
## TODO: generalize this module.
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
inherit (pkgs) liminix;
|
||||
@@ -22,23 +27,31 @@ in
|
||||
|
||||
config.boot.zyxel-dual-image = config.system.callService ./service.nix {
|
||||
ensureActiveImage = mkOption {
|
||||
type = types.enum [ "primary" "secondary" ];
|
||||
type = types.enum [
|
||||
"primary"
|
||||
"secondary"
|
||||
];
|
||||
default = "primary";
|
||||
description = ''At boot, ensure that the active image is the one specified.
|
||||
description = ''
|
||||
At boot, ensure that the active image is the one specified.
|
||||
|
||||
If you are already on a broken image, you need to manually boot
|
||||
into the right image via `atgo <image index>` in U-Boot.
|
||||
If you are already on a broken image, you need to manually boot
|
||||
into the right image via `atgo <image index>` in U-Boot.
|
||||
'';
|
||||
};
|
||||
|
||||
kernelCommandLineSource = mkOption {
|
||||
type = types.enum [ "/proc/cmdline" "/proc/device-tree/chosen/bootargs" ];
|
||||
type = types.enum [
|
||||
"/proc/cmdline"
|
||||
"/proc/device-tree/chosen/bootargs"
|
||||
];
|
||||
default = "/proc/device-tree/chosen/bootargs";
|
||||
description = ''Kernel command line arguments source file.
|
||||
On MIPS, Liminix embeds the kernel command line in /proc/device-tree/chosen/bootargs-override.
|
||||
description = ''
|
||||
Kernel command line arguments source file.
|
||||
On MIPS, Liminix embeds the kernel command line in /proc/device-tree/chosen/bootargs-override.
|
||||
|
||||
In this instance, it does not get concatenated with `/proc/cmdline`.
|
||||
Therefore you may prefer to source it from another place, like `/proc/device-tree/chosen/bootargs`.
|
||||
In this instance, it does not get concatenated with `/proc/cmdline`.
|
||||
Therefore you may prefer to source it from another place, like `/proc/device-tree/chosen/bootargs`.
|
||||
'';
|
||||
};
|
||||
|
||||
|
@@ -1,13 +1,20 @@
|
||||
{
|
||||
liminix
|
||||
, lib
|
||||
, zyxel-bootconfig
|
||||
liminix,
|
||||
lib,
|
||||
zyxel-bootconfig,
|
||||
}:
|
||||
{
|
||||
ensureActiveImage,
|
||||
primaryMtdPartition,
|
||||
secondaryMtdPartition,
|
||||
bootConfigurationMtdPartition,
|
||||
kernelCommandLineSource,
|
||||
}:
|
||||
{ ensureActiveImage, primaryMtdPartition, secondaryMtdPartition, bootConfigurationMtdPartition, kernelCommandLineSource }:
|
||||
let
|
||||
inherit (liminix.services) oneshot;
|
||||
activeImageIndex = if ensureActiveImage == "primary" then 0 else 1;
|
||||
in oneshot {
|
||||
in
|
||||
oneshot {
|
||||
name = "zyxel-boot-configure";
|
||||
up = ''
|
||||
set -- $(cat /proc/device-tree/chosen/bootargs)
|
||||
|
Reference in New Issue
Block a user