port service manager to s6

still a lot of cleanup to do (e.g. support dbus service types), but it boots to a usable desktop
This commit is contained in:
2024-03-18 02:02:24 +00:00
parent 63af94383b
commit 2336767059
6 changed files with 126 additions and 37 deletions

View File

@@ -79,6 +79,8 @@ in
"powertop" "powertop"
"pstree" "pstree"
"ripgrep" "ripgrep"
"s6"
"s6-rc" # service manager
"screen" "screen"
"smartmontools" # smartctl "smartmontools" # smartctl
# "socat" # "socat"
@@ -763,6 +765,9 @@ in
rustc = {}; rustc = {};
s6 = {};
s6-rc = {};
sane-open-desktop.sandbox.enable = false; #< trivial script, and all our deps are sandboxed sane-open-desktop.sandbox.enable = false; #< trivial script, and all our deps are sandboxed
sane-open-desktop.suggestedPrograms = [ sane-open-desktop.suggestedPrograms = [
"gdbus" "gdbus"

View File

@@ -16,7 +16,10 @@ let
export XDG_CURRENT_DESKTOP=sway export XDG_CURRENT_DESKTOP=sway
echo "launching sway (sway.desktop)..." | ${systemd-cat} --identifier=sway echo "launching sway (sway.desktop)..." | ${systemd-cat} --identifier=sway
exec ${configuredSway}/bin/sway 2>&1 | ${systemd-cat} --identifier=sway # delete DISPLAY-related vars from env before launch, else sway will try to connect to a remote display.
# (consider: nested sway sessions, where sway actually has a reason to read these)
exec env -u DISPLAY -u WAYLAND_DISPLAY \
${configuredSway}/bin/sway 2>&1 | ${systemd-cat} --identifier=sway
''; '';
in in
pkgs.symlinkJoin { pkgs.symlinkJoin {
@@ -194,6 +197,7 @@ in
# bind ALL of ~/.config/sway into the sandbox instead of just the individual configs. # bind ALL of ~/.config/sway into the sandbox instead of just the individual configs.
# this way `swaymsg -- reload` can work even if the fd for ~/.config/sway/config changes. # this way `swaymsg -- reload` can work even if the fd for ~/.config/sway/config changes.
".config/sway" ".config/sway"
".config/s6"
]; ];
sandbox.extraConfig = [ sandbox.extraConfig = [
"--sane-sandbox-keep-namespace" "pid" "--sane-sandbox-keep-namespace" "pid"
@@ -218,26 +222,50 @@ in
xwayland = if config.sane.programs.xwayland.enabled then "enable" else "disable"; xwayland = if config.sane.programs.xwayland.enabled then "enable" else "disable";
}; };
services.sway-session = { env.XDG_CURRENT_DESKTOP = "sway";
description = "sway-session: active iff sway desktop environment is baseline operational"; # TODO: don't hardcode user id!
documentation = [ env.SWAYSOCK = "/run/user/1000/sway-ipc.sock";
"https://github.com/swaywm/sway/issues/7862" # TODO: ensure this is reliable? might not work across sway restarts, etc.
"https://github.com/alebastr/sway-systemd" env.DISPLAY = ":0";
]; env.WAYLAND_DISPLAY = "wayland-1";
# we'd like to start graphical-session after sway is ready, but it's marked `RefuseManualStart` because Lennart. # services.sway-session = {
# instead, create `sway-session.service` which `bindsTo` `graphical-session.target`. # description = "sway-session: active iff sway desktop environment is baseline operational";
# we can manually start `sway-session`, and the `bindsTo` means that it will start `graphical-session`, # documentation = [
# and then track `graphical-session`s state (that is: it'll stop when graphical-session stops). # "https://github.com/swaywm/sway/issues/7862"
# # "https://github.com/alebastr/sway-systemd"
# additionally, set `ConditionEnvironment` to guard that the sway environment variables *really have* been imported into systemd. # ];
unitConfig.ConditionEnvironment = "SWAYSOCK";
# requiredBy = [ "graphical-session.target" ];
before = [ "graphical-session.target" ];
bindsTo = [ "graphical-session.target" ];
# # we'd like to start graphical-session after sway is ready, but it's marked `RefuseManualStart` because Lennart.
# # instead, create `sway-session.service` which `bindsTo` `graphical-session.target`.
# # we can manually start `sway-session`, and the `bindsTo` means that it will start `graphical-session`,
# # and then track `graphical-session`s state (that is: it'll stop when graphical-session stops).
# #
# # additionally, set `ConditionEnvironment` to guard that the sway environment variables *really have* been imported into systemd.
# unitConfig.ConditionEnvironment = "SWAYSOCK";
# # requiredBy = [ "graphical-session.target" ];
# before = [ "graphical-session.target" ];
# bindsTo = [ "graphical-session.target" ];
# serviceConfig = {
# ExecStart = "${pkgs.coreutils}/bin/true";
# Type = "oneshot";
# RemainAfterExit = true;
# };
# };
# services.sway-session = {
# description = "sway-session: meta-service for everything wanted by sway (after launch)";
# wants = [ "graphical-session.target" ];
# };
services.sway = {
description = "sway: launch it";
wantedBy = [ "default.target" ];
serviceConfig = { serviceConfig = {
ExecStart = "${pkgs.coreutils}/bin/true"; ExecStart = "${cfg.package}/bin/sway";
# ExecStart = "${lib.getBin pkgs.glib}/bin/gio launch sway.desktop";
# ExecStart = "${pkgs.sane-open-desktop}/bin/sane-open-desktop sway.desktop";
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
}; };

View File

@@ -258,6 +258,10 @@ exec --no-startup-id dbus-update-activation-environment --systemd PATH XDG_DATA_
# signal to systemd that sway is active, # signal to systemd that sway is active,
# and therefore let it start any downstream services (e.g. apps that would like to auto-start) # and therefore let it start any downstream services (e.g. apps that would like to auto-start)
# see `systemctl --user cat sway-session` for links to docs # see `systemctl --user cat sway-session` for links to docs
exec --no-startup-id systemctl start --user sway-session.service # exec --no-startup-id systemctl start --user sway-session.service
# TODO: remove this. likely, the variables above can/should be set *before* launching the service manager at all.
# and if need be we can replace this line with a "notify ready" signal to the service manager instead.
exec --no-startup-id s6-rc -l $HOME/.config/s6/live start graphical-session
@extra_lines@ @extra_lines@

View File

@@ -119,15 +119,28 @@ in
}; };
}; };
# lib.mkAfter so that launching the DE happens *after* any other .profile setup. fs.".profile".symlink.text = lib.mkMerge [
# alternatively, we could recurse: exec a new login shell with some env-var signalling to not launch the DE, (lib.mkBefore ''
# run with `-c "{cfg.afterLogin}"` primarySessionCommands=()
fs.".profile".symlink.text = lib.mkAfter '' initPrimarySession() {
# if already running a desktop environment, or if running from ssh, then `tty` will show /dev/pts/NN. for c in "''${primarySessionCommands[@]}"; do
if [ "$(tty)" = "/dev/${tty}" ]; then eval "$c"
${tryLaunchDefaultDesktop}/bin/tryLaunchDefaultDesktop done
fi }
''; '')
# lib.mkAfter so that launching the DE happens *after* any other .profile setup.
(lib.mkAfter ''
# if already running a desktop environment, or if running from ssh, then `tty` will show /dev/pts/NN.
if [ "$(tty)" = "/dev/${tty}" ]; then
if (( ''${#primarySessionCommands[@]} )); then
echo "launching primary session commands in ${builtins.toString cfg.config.delay}s: ''${primarySessionCommands[*]}"
# if the `sleep` call here is `Ctrl+C'd`, then it'll exit false and the desktop isn't launched.
sleep ${builtins.toString cfg.config.delay} && \
initPrimarySession
fi
fi
'')
];
# N.B.: this sandboxing applies to `unl0kr` itself -- the on-screen-keyboard; # N.B.: this sandboxing applies to `unl0kr` itself -- the on-screen-keyboard;
# NOT to the wrapper which invokes `login`. # NOT to the wrapper which invokes `login`.

View File

@@ -59,19 +59,19 @@ in
wantedBy = [ "graphical-session.target" ]; wantedBy = [ "graphical-session.target" ];
serviceConfig = { serviceConfig = {
ExecStart="${cfg.package}/libexec/xdg-desktop-portal"; # tracking issue for having xdg-desktop-portal locate portals via more standard directories, obviating this var:
# - <https://github.com/flatpak/xdg-desktop-portal/issues/603>
# i can actually almost omit it today; problem is that if you don't set it it'll look for `sway-portals.conf` in ~/.config/xdg-desktop-portal
# but then will check its *own* output dir for {gtk,wlr}.portal.
# arguable if that's a packaging bug, or limitation...
ExecStart=''env XDG_DESKTOP_PORTAL_DIR="$HOME/.config/xdg-desktop-portal" ${cfg.package}/libexec/xdg-desktop-portal'';
Type = "dbus"; Type = "dbus";
BusName = "org.freedesktop.portal.Desktop"; BusName = "org.freedesktop.portal.Desktop";
Restart = "always"; Restart = "always";
RestartSec = "10s"; RestartSec = "10s";
}; };
# tracking issue for having xdg-desktop-portal locate portals via more standard directories, obviating this var: # environment.XDG_DESKTOP_PORTAL_DIR = "%E/xdg-desktop-portal";
# - <https://github.com/flatpak/xdg-desktop-portal/issues/603>
# i can actually almost omit it today; problem is that if you don't set it it'll look for `sway-portals.conf` in ~/.config/xdg-desktop-portal
# but then will check its *own* output dir for {gtk,wlr}.portal.
# arguable if that's a packaging bug, or limitation...
environment.XDG_DESKTOP_PORTAL_DIR = "%E/xdg-desktop-portal";
# environment.G_MESSAGES_DEBUG = "all"; #< also applies to all apps launched by the portal # environment.G_MESSAGES_DEBUG = "all"; #< also applies to all apps launched by the portal
}; };

View File

@@ -103,7 +103,7 @@ let
inherit name; inherit name;
run = service.serviceConfig.ExecStart; run = service.serviceConfig.ExecStart;
depends = service.wants ++ builtins.attrNames ( depends = service.wants ++ builtins.attrNames (
lib.filterAttrs (_: cfg: lib.elem name cfg.wantedBy) services lib.filterAttrs (_: cfg: lib.elem name cfg.wantedBy || lib.elem "${name}.service" cfg.wantedBy) services
); );
}) })
services services
@@ -131,7 +131,46 @@ in
sources = genServices (s6SvcsFromConfigServices (implicitServices // config.services)); sources = genServices (s6SvcsFromConfigServices (implicitServices // config.services));
in { in {
fs.".config/s6/sources".symlink.target = sources; fs.".config/s6/sources".symlink.target = sources;
fs.".config/s6/compiled".symlink.target = compileServices sources; # N.B.: `compiled` needs to be writable (for locks -- maybe i can use symlinks to dodge this someday),
# so write this nearby and copy it over to `compiled` later
fs.".config/s6/compiled-static".symlink.target = compileServices sources;
fs.".profile".symlink.text = ''
function startS6() {
local S6_TARGET="''${1:-default}"
local COMPILED=$HOME/.config/s6/compiled
local LIVE=$HOME/.config/s6/live
local SCANDIR=$HOME/.config/s6/scandir
rm -rf $SCANDIR
mkdir $SCANDIR
s6-svscan $SCANDIR &
local SVSCAN=$!
# the scandir is just links back into the compiled dir,
# so the compiled dir therefore needs to be writable:
rm -rf $COMPILED
cp --dereference -R $COMPILED-static $COMPILED
chmod -R 0700 $COMPILED
s6-rc-init -c $COMPILED -l $LIVE -d $SCANDIR
# echo default: deps
# s6-rc-db -c $COMPILED contents default
# echo graphical-session: deps
# s6-rc-db -c $COMPILED contents graphical-session
if [ -n "$S6_TARGET" ]; then
s6-rc -l $LIVE start "$S6_TARGET"
fi
echo "s6 initialized: Ctrl+C to stop"
wait $SVSCAN
}
primarySessionCommands+=('startS6 &')
'';
})); }));
}; };
} }