commit 49d1703428f1f83bdc557517932796a1f031430e
parent 1d337588f9c7955a3ca1a912698a3f4e94cc4c18
Author: Daniel Barlow <dan@telent.net>
Date: Sat, 15 Jun 2024 14:59:34 +0100
add s6-rc-up-tree: start reverse deps of controlled service
When s6-rc stops a service, it also stops everything that
depends on it. but when it starts a service it starts only
that service, so we have to go through the other services
depending on it and figure out if they should be started too.
Diffstat:
8 files changed, 60 insertions(+), 4 deletions(-)
diff --git a/modules/s6/default.nix b/modules/s6/default.nix
@@ -8,7 +8,7 @@ let
stdenvNoCC;
inherit (lib.lists) unique concatMap;
inherit (pkgs.pseudofile) dir symlink;
- inherit (pkgs.liminix.services) bundle;
+ inherit (pkgs.liminix.services) oneshot bundle;
s6-rc-db =
let
@@ -31,12 +31,25 @@ let
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
+ controlled = oneshot {
+ name = "controlled";
+ up = ''
+ mkdir -p /run/services/controlled
+ for s in $(s6-rc-db -d dependencies controlled); do
+ touch /run/services/controlled/$s
+ done
+ '';
+ down = "rm -r /run/services/controlled";
+ };
+
defaultStart =
builtins.filter
(s: !(isDependentOnControlled s)) allServices;
defaultDefaultTarget = bundle {
name = "default";
- contents = defaultStart;
+ contents = defaultStart ++ [controlled];
};
servicesAttrs = {
default = defaultDefaultTarget;
diff --git a/pkgs/default.nix b/pkgs/default.nix
@@ -98,6 +98,7 @@ in {
run-liminix-vm = callPackage ./run-liminix-vm {};
s6-init-bin = callPackage ./s6-init-bin {};
s6-rc-database = callPackage ./s6-rc-database {};
+ s6-rc-up-tree = callPackage ./s6-rc-up-tree {};
# schnapps is written by Turris and provides a high-level interface
# to btrfs snapshots. It may be useful on the Turris Omnia to
@@ -112,6 +113,7 @@ in {
uevent-watch = callPackage ./uevent-watch {};
usb-modeswitch = callPackage ./usb-modeswitch {};
writeAshScript = callPackage ./write-ash-script {};
+ writeAshScriptBin = callPackage ./write-ash-script/bin.nix {};
writeFennel = callPackage ./write-fennel {};
writeFennelScript = callPackage ./write-fennel-script {};
}
diff --git a/pkgs/liminix-tools/services/builder.sh b/pkgs/liminix-tools/services/builder.sh
@@ -16,6 +16,8 @@ done
if test -n "$controller" ; then
d=$(dirname $(cd ${controller} && ls -d */type))
echo "$d)" > $out/${name}/controller
+ # ^ why is there a closing paren here?
+ touch $out/${name}/dependencies.d/controlled
fi
for i in timeout-up timeout-down run notification-fd up down finish consumer-for producer-for pipeline-name restart-on-upgrade; do
diff --git a/pkgs/s6-rc-up-tree/default.nix b/pkgs/s6-rc-up-tree/default.nix
@@ -0,0 +1,4 @@
+{
+ writeAshScriptBin
+}:
+writeAshScriptBin "s6-rc-up-tree" {} (builtins.readFile ./s6-rc-up-tree.sh)
diff --git a/pkgs/s6-rc-up-tree/s6-rc-up-tree.sh b/pkgs/s6-rc-up-tree/s6-rc-up-tree.sh
@@ -0,0 +1,24 @@
+service=$1
+
+blocks=""
+for controlled in $(cd /run/services/controlled/ && echo *); do
+ down=$(s6-rc -un0 change $controlled)
+ echo $controlled $down
+ if test -n "$down"; then
+ blocks="$blocks $controlled "
+ fi
+done
+
+for s in $(s6-rc-db -d all-dependencies $service); do
+ for dep in $(s6-rc-db all-dependencies $s); do
+ case "$blocks" in
+ "* $dep *")
+ echo "not starting $s, blocked by $dep"
+ ;;
+ *)
+ echo "starting $s because $service"
+ s6-rc -u change $s
+ ;;
+ esac
+ done
+done
diff --git a/pkgs/s6-rc-up-tree/test-list b/pkgs/s6-rc-up-tree/test-list
@@ -0,0 +1,7 @@
+
+the service starts
+uncontrolled descendants start
+controlled descendants don't start
+descendants which depend on a _different_ controlled service, which is down, don't start
+descendants which depend on a _different_ controlled service, which is up, do start
+
diff --git a/pkgs/uevent-watch/default.nix b/pkgs/uevent-watch/default.nix
@@ -8,17 +8,21 @@
, fennel
, stdenv
, fennelrepl
+, s6-rc-up-tree
+, makeWrapper
}:
stdenv.mkDerivation {
name = "uevent-watch";
src = ./.;
- nativeBuildInputs = [ fennelrepl ];
+ nativeBuildInputs = [ fennelrepl makeWrapper ];
+ propagatedBuildInputs = [ s6-rc-up-tree ];
installPhase = ''
mkdir -p $out/bin
cp -p ${writeFennel "uevent-watch" {
packages = [fennel anoia nellie lualinux];
mainFunction = "run";
} ./watch.fnl} $out/bin/uevent-watch
+ wrapProgram $out/bin/uevent-watch --prefix PATH : "${s6-rc-up-tree}/bin"
'';
checkPhase = ''
fennelrepl ./test.fnl
diff --git a/pkgs/uevent-watch/watch.fnl b/pkgs/uevent-watch/watch.fnl
@@ -18,7 +18,7 @@
(fn start-service [devname linkname service]
(match (if linkname (symlink (.. "/dev/" devname) linkname) true)
- ok (pcall system (%% "s6-rc -b -u change %q" service))
+ ok (pcall system (%% "s6-rc-up-tree %q" service))
(nil err) false))
(fn stop-service [linkname service]