switch to s6-linux-init and s6-rc

This is at the point where it runs a getty and a pile of s6-supervise
processes, though it doesn't seem to run the things being supervised
This commit is contained in:
Daniel Barlow 2022-09-21 23:01:21 +01:00
parent 6be5b90c96
commit 45025f128a
12 changed files with 404 additions and 22 deletions

View file

@ -1,10 +1,6 @@
# Liminix
Līminis + Nix
* Līminis : Latin, genitive declension of limen. "Of the threshold"
* Nix : a tool for reproducible and declarative configuration management
* Liminix : a Nix-based system for configuring consumer wifi routers
A Nix-based system for configuring consumer wifi routers.
## What is this?
@ -16,6 +12,11 @@ This is not NixOS-on-your-router: it's aimed at devices that are
underpowered for the full NixOS experience. It uses busybox tools,
musl instead of GNU libc, and s6-rc instead of systemd.
The Liminix name comes from Liminis, in Latin the genitive declension
of "limen", or "of the threshold". Your router stands at the threshold
of your (online) home and everything you send to/receive from the
outside word goes across it.
## Building
@ -52,3 +53,16 @@ took full advantage of the basic application armoring features
provided by the operating system. Indeed, only one or two models even
came close, and no brand did well consistently across all models
tested"
-----
s6/ directory has the result of running s6-linux-init-maker, plus edits
to the scripts for s6-rc
- need to fix the bin/ directory (maybe they were copied from
s6-linux-init?)
- maybe the run-image directory can be added as a squashfs source directory?

View file

@ -3,6 +3,7 @@ let
inherit (pkgs)
callPackage
closureInfo
lib
runCommand
s6-rc
stdenv
@ -46,36 +47,42 @@ let
mount -t proc none /proc
mkdir -p /run/services
'';
storefs = callPackage <nixpkgs/nixos/lib/make-squashfs.nix> {
storeContents = [ rcS pkgs.pkgsStatic.busybox s6db pkgs.s6-linux-init ] ++ config.packages ;
# comp = "xz -Xdict-size 100%"
};
s6-pseudofiles = pkgs.s6-init-files;
pseudofiles = writeText "pseudofiles" ''
/ d 0755 0 0
/bin d 0755 0 0
/etc d 0755 0 0
/run d 0755 0 0
/dev d 0755 0 0
/dev/console c 0600 root root 5 1
/dev/null c 0666 root root 1 3
/dev/tty c 0777 root root 5 0
/dev/zero c 0666 root root 1 5
/dev/tty1 c 0777 root root 4 1
/dev/tty2 c 0777 root root 4 2
/dev/tty3 c 0777 root root 4 3
/dev/tty4 c 0777 root root 4 4
/dev/zero c 0666 root root 1 5
/dev/tty c 0777 root root 5 0
/dev/console c 0600 root root 5 1
/proc d 0555 root root
/dev/pts d 0755 0 0
/etc/init.d d 0755 0 0
/bin/init s 0755 0 0 ${pkgs.pkgsStatic.busybox}/bin/init
/bin/init s 0755 0 0 /etc/s6-linux-init/current/bin/init
/bin/sh s 0755 0 0 ${pkgs.pkgsStatic.busybox}/bin/sh
/bin/busybox s 0755 0 0 ${pkgs.pkgsStatic.busybox}/bin/busybox
/bin/busybox s 0755 0 0 ${pkgs.busybox}/bin/busybox
/etc/init.d/rcS s 0755 0 0 ${rcS}
/etc/s6-rc d 0755 0 0
/etc/s6-rc/compiled s 0755 0 0 ${s6db}/compiled
/etc/passwd f 0644 0 0 echo "root::0:0:root:/:/bin/sh"
'';
in runCommand "frob-squashfs" {} ''
cp ${storefs} ./store.img
chmod +w store.img
${pkgs.buildPackages.squashfsTools}/bin/mksquashfs - store.img -no-recovery -quiet -no-progress -root-becomes store -p "/ d 0755 0 0"
${pkgs.buildPackages.squashfsTools}/bin/mksquashfs - store.img -no-recovery -quiet -no-progress -root-becomes nix -pf ${pseudofiles}
cp store.img $out
''
storefs = callPackage <nixpkgs/nixos/lib/make-squashfs.nix> {
storeContents = [ pseudofiles pkgs.strace s6-pseudofiles rcS pkgs.pkgsStatic.busybox s6db pkgs.s6-linux-init ] ++ config.packages ;
# comp = "xz -Xdict-size 100%"
};
in runCommand "frob-squashfs" {
nativeBuildInputs = with pkgs.buildPackages; [ squashfsTools qprint ];
} ''
cp ${storefs} ./store.img
chmod +w store.img
mksquashfs - store.img -no-recovery -quiet -no-progress -root-becomes store -p "/ d 0755 0 0"
mksquashfs - store.img -no-recovery -quiet -no-progress -root-becomes nix -pf ${pseudofiles} -pf ${s6-pseudofiles}
cp store.img $out
''

View file

@ -1,3 +1,5 @@
final: prev: {
# s6-rc = final.callPackage ./pkgs/s6-rc;
pseudofile = final.callPackage ./pkgs/pseudofile {};
s6-init-files = final.callPackage ./pkgs/s6-init-files {};
strace = prev.strace.override { libunwind = null; };
}

View file

@ -0,0 +1,37 @@
{
writeText
, lib
}:
filename : attrset :
let
inherit (lib.debug) traceSeqN;
inherit (lib.attrsets) mapAttrsToList;
visit = prefix: attrset:
let
qprint = msg : builtins.replaceStrings ["\n" "=" "\""] ["=0A" "=3D" "=22"] msg;
l =
mapAttrsToList
(filename: attrs:
let
attrs' = {type = "f"; } // attrs;
mode = if attrs ? mode then attrs.mode else
(if attrs'.type == "d" then "0755" else "0644");
line = "${prefix}/${filename} ${attrs'.type} ${mode} 0 0";
in
if attrs'.type == "f" then
"${line} echo -n \"${qprint attrs'.file}\" |qprint -d"
else if attrs'.type == "d" then
(visit "${prefix}/${filename}" attrs.contents) +
"\n" + line
else if attrs'.type == "s" then
"${line} ${attrs'.target}"
else if attrs'.type == "l" then
"${prefix}/${filename} l ${attrs'.target}"
else if attrs'.type == "i" then
"${line} ${attrs.subtype}"
else
line)
attrset;
in builtins.concatStringsSep "\n" l;
res = (visit "" attrset);
in writeText filename res

View file

@ -0,0 +1,156 @@
{
execline
, s6
, s6-linux-init
, s6-rc
, pseudofile
, lib
, stdenvNoCC
, busybox
} :
let
initscripts = stdenvNoCC.mkDerivation {
name = "s6-scripts";
src = ./scripts;
phases = ["unpackPhase" "installPhase" ];
buildInputs = [busybox];
installPhase = ''
mkdir $out
cp -r $src $out/scripts
chmod -R +w $out
patchShebangs $out/scripts
'';
};
dir = contents: { type = "d"; inherit contents; };
symlink = target: { type = "s"; inherit target; };
hpr = arg: "#!${execline}/bin/execlineb -S0\n${s6-linux-init}/bin/s6-linux-init-hpr ${arg} \$@";
bin = dir {
shutdown = symlink "${s6-linux-init}/bin/s6-linux-init-shutdown";
telinit = symlink "${s6-linux-init}/bin/s6-linux-init-telinit";
reboot = { type="f"; file = hpr "-r"; mode="0755"; };
poweroff = { type="f"; file = hpr "-p"; mode="0755"; };
halt = { type="f"; file = hpr "-h"; mode="0755"; };
init = {
type="f"; mode="0755";
file = "#!${execline}/bin/execlineb -S0\n${s6-linux-init}/bin/s6-linux-init -c /etc/s6-linux-init/current -m 0022 -p ${lib.makeBinPath [execline s6-linux-init s6-rc]}:/usr/bin:/bin -d /dev -- \"\\$@\"";
};
};
scripts = symlink "${initscripts}/scripts";
env = dir {};
run-image = dir {
service = dir {
s6-linux-init-runleveld = dir {
notification-fd = { file = "3"; };
run = {
file = ''
#!${execline}/bin/execlineb -P
${execline}/bin/fdmove -c 2 1
${execline}/bin/bin/fdmove 1 3
${s6}/s6-ipcserver -1 -a 0700 -c 1 -- s
${s6}/bin/s6-sudod -dt30000 -- "/etc/s6-linux-init/current"/scripts/runlevel
'';
mode = "0755";
};
};
s6-linux-init-shutdownd = dir {
fifo = {
type = "i";
subtype = "f";
mode = "0600";
};
run = {
file = ''
#!${execline}/bin/execlineb -P
${s6-linux-init}/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
'';
mode = "0755";
};
};
s6-svscan-log = dir {
fifo = {
type = "i";
subtype = "f";
mode = "0600";
};
notification-fd = { file = "3"; };
run = {
file = ''
#!${execline}/bin/execlineb -P
${execline}/bin/redirfd -w 1 /dev/null
${execline}/bin/redirfd -rnb 0 fifo
${s6}/bin/s6-log -bpd3 -- t /run/uncaught-logs
'';
mode = "0755";
};
};
getty = dir {
run = {
file = ''
#!${execline}/bin/execlineb -P
${busybox}/bin/getty -l ${busybox}/bin/login 38400 /dev/console
'';
mode = "0755";
};
};
".s6-svscan" =
let
quit = message: ''
#!${execline}/bin/execlineb -P
${execline}/bin/redirfd -w 2 /dev/console
${execline}/bin/bin/fdmove -c 1 2
${execline}/bin/foreground { ${s6-linux-init}/bin/s6-linux-init-echo -- ${message} }
${s6-linux-init}/bin/s6-linux-init-hpr -fr
'';
shutdown = action: ''
#!${execline}/bin/execlineb -P
${s6-linux-init}/bin/s6-linux-init-hpr -a #{action} -- now
'';
empty = "#!${execline}/bin/execlineb -P\n";
in dir {
crash = {
file = quit "s6-svscan crashed. Rebooting.";
mode = "0755";
};
finish = {
file = quit "s6-svscan exited. Rebooting.";
mode = "0755";
};
SIGINT = {
file = shutdown "-r";
mode = "0755";
};
SIGPWR = {
file = shutdown "-p";
mode = "0755";
};
SIGQUIT = {
file = empty;
mode = "0755";
};
SIGTERM = {
file = empty;
mode = "0755";
};
SIGUSR1 = {
file = shutdown "-p";
mode = "0755";
};
SIGUSR2 = {
file = shutdown "-h";
mode = "0755";
};
SIGWINCH = {
file = empty;
mode = "0755";
};
};
};
uncaught-logs = (dir {}) // {mode = "2750";};
};
structure = { etc = dir { s6-linux-init = dir { current = dir {
inherit bin scripts env run-image;
};};};};
in pseudofile "pseudo.s6-init" structure

View file

@ -0,0 +1,42 @@
#!/usr/bin/env sh
rl="$1"
shift
### argv now contains the arguments of the kernel command line that are
### not of the form key=value. (The key=value arguments were stored by
### s6-linux-init into an envdir, if instructed so via the -s option.)
### Normally this argv remains unused because programs that need the
### kernel command line usually read it later on from /proc/cmdline -
### but just in case, it's available here.
### 1. Early preparation
### This is done only once at boot time.
### Ideally, this phase should just initialize the service manager.
### If your services are managed by s6-rc:
### (replace /run/service with your scandir)
s6-rc-init /run/service -d -c /etc/s6-rc/compiled
### 2. Starting the wanted set of services
### This is also called every time you change runlevels with telinit.
### (edit the location to suit your installation)
### By default, $rl is the string "default", unless you changed it
### via the -D option to s6-linux-init-maker.
### Numeric arguments from 1 to 5 on the kernel command line will
### override the default.
exec /etc/s6-linux-init/current/scripts/runlevel "$rl"
### If this script is run in a container, then 1. and 2. above do not
### apply and you should just call your CMD, if any, or let your
### services run.
### Something like this:
# if test -z "$*" ; then return 0 ; fi
# $@
# echo $? > /run/s6-linux-init-container-results/exitcode
# halt

View file

@ -0,0 +1,19 @@
#!/usr/bin/env sh
### Things to do before hardware halt/reboot/poweroff.
### Ideally, it should be a single call to the service manager,
### telling it to bring all the services down.
### If your s6-linux-init-maker invocation was made with the -1
### option, messages from rc.shutdown will appear on /dev/console
### as well as be logged by the catch-all logger.
### If your s6-linux-init-maker invocation did NOT include the -1
### option, messages from rc.shutdown will only be logged by the
### catch-all logger and will NOT appear on /dev/console. In order
### to print them to /dev/console instead, you may want to
### uncomment the following line:
exec >/dev/console 2>&1
### If your services are managed by s6-rc:
exec s6-rc -v2 -bDa change

View file

@ -0,0 +1,18 @@
#!/nix/store/xbdqbi2mscmhl5wcpbgpjdwxbsrvpkil-bash-5.1-p16/bin/sh -e
### Things to do *right before* the machine gets rebooted or
### powered off, at the very end of the shutdown sequence,
### when all the filesystems are unmounted.
### This is a last resort hook; normally nothing should be
### done here (your rc.shutdown script should have taken care
### of everything) and you should leave this script empty.
### Some distributions, however, may need to perform some
### actions after unmounting the filesystems: typically if
### an additional teardown action is required on a filesystem
### after unmounting it, or if the system needs to be
### pivot_rooted before it can be shut down, etc.
### Those are all exceptional cases. If you don't know for
### certain that you need to do something here, you don't.

View file

@ -0,0 +1,12 @@
#!/usr/bin/env sh -e
### This script is called once at boot time by rc.init, and is
### also called by the runleveld service every time the user
### requests a machine state change via telinit.
### Ideally, it should just be a call to the service manager.
test "$#" -gt 0 || { echo 'runlevel: fatal: too few arguments' 1>&2 ; exit 100 ; }
### If your services are managed by s6-rc:
exec s6-rc -v2 -up change "$1"

View file

@ -0,0 +1,13 @@
/service/s6-linux-init-runleveld/notification-fd f 0644 0 0 echo -n "3" |qprint -d
/service/s6-linux-init-runleveld/run f 0755 0 0 echo -n " hello=0A newline=0A" |qprint -d
/service/s6-linux-init-runleveld d 0755 0 0
/service/s6-linux-init-shutdownd/fifo i 0600 0 0 f
/service/s6-linux-init-shutdownd/run f 0755 0 0 echo -n "s6-linux-init/bin/s6-linux-init-shutdownd -c =22/etc/s6-linux-init/current=22 -g 3000=0A" |qprint -d
/service/s6-linux-init-shutdownd d 0755 0 0
/service/s6-svscan-log/fifo i 0600 0 0 f
/service/s6-svscan-log/notification-fd f 0644 0 0 echo -n "3" |qprint -d
/service/s6-svscan-log/run f 0644 0 0 echo -n "gdsgdfgsdgf=0A" |qprint -d
/service/s6-svscan-log d 0755 0 0
/service d 0755 0 0
/uncaught-logs d 2750 0 0

17
tests/pseudofiles/run.sh Executable file
View file

@ -0,0 +1,17 @@
set -e
expr=$(cat <<"EXPR"
let
overlay = import ./overlay.nix;
nixpkgs = import <nixpkgs> ( {overlays = [overlay]; });
structure = import ./tests/pseudofiles/structure.nix;
in nixpkgs.pkgs.pseudofile "pseudo.s6-init" structure
EXPR
)
NIXPKGS_ALLOW_UNSUPPORTED_SYSTEM=1 nix-build -E "${expr}" -o tests/pseudofiles/result $*
diff tests/pseudofiles/result tests/pseudofiles/result.expected
test -f /tmp/out.squashfs && rm /tmp/out.squashfs
nix-shell -p squashfsTools -p qprint --run "mksquashfs - /tmp/out.squashfs -p '/ d 755 0 0' -pf tests/pseudofiles/result -quiet -no-progress"
foo="$(nix-shell -p squashfsTools --run 'unsquashfs -cat /tmp/out.squashfs service/s6-linux-init-runleveld/run')"
test "$foo" = "$(printf "hello\nworld")"

View file

@ -0,0 +1,45 @@
let
dir = contents: { type = "d"; inherit contents; };
structure = {
service = dir {
s6-linux-init-runleveld = dir {
notification-fd = { file = "3"; };
run = {
file = ''
hello
world
'';
mode = "0755";
};
};
s6-linux-init-shutdownd = dir {
fifo = {
type = "i";
subtype = "f";
mode = "0600";
};
run = {
file = ''
s6-linux-init/bin/s6-linux-init-shutdownd -c "/etc/s6-linux-init/current" -g 3000
'';
mode = "0755";
};
};
s6-svscan-log = dir {
fifo = {
type = "i";
subtype = "f";
mode = "0600";
};
notification-fd = { file = "3"; };
run = {
file = ''
gdsgdfgsdgf
'';
};
};
};
uncaught-logs = (dir {}) // {mode = "2750";};
};
in structure