Links:
Installation guide
elogind-usersv
s6-user
I've been working on a way to have proper per-user services, like with systemd --user. The ones that start when you login, and stop when you logout, not just desktop autostart scripts that start/stop god knows when, and aren't even supervised. It's kind of a waste, having a fucking s6 in your system and not use it for actual process supervision.
The problems with the Artix s6 setup are:
s6-svscan supervises user services, elogind handles login/logout and the runtime directory (/run/user/$UID). elogind doesn't (and shouldn't) spawn s6-svscan or ensure it stays running.
s6-frontend provides the s6 --user command, but it still doesn't distinguish persistent user services from system services, only live ones.
There are 2 existing solutions to problem 1:
Turnstile - a login manager, but it can also run alongside elogind, with the runtime directory left to elogind. In that setup it does what I want:
- On login it spawns a per-user service manager, and its PAM blocks the login until the backend reports ready.
- It has a simple backend protocol, so any service manager works once you write a backend for it.
- It keeps the runtime directory alive for the manager's lifetime by holding an elogind session open (via
pam_elogind in turnstiled's PAM stack). So even after the user logs out of their last real session, elogind still sees a session and won't wipe /run/user/$UID until the manager has gracefully finished, with a timeout.
That's basically everything I want from a per-user service manager launcher. The dealbreaker is: turnstile also counts user sessions itself, with its own PAM, so it becomes a second source of truth alongside elogind. If elogind or turnstile crashes, their counters desync, and you get either a stale session held by turnstile, or turnstile stopping the manager because it thinks nobody's logged in, while elogind still has an active session, leaving that user without a service manager.
Userspawn - depends on elogind, listens to its DBus, spawns and kills per-user service managers. Very minimal, but doesn't suit me, because it doesn't make the user wait until the service manager reports ready, and it doesn't gracefully shut the service manager down, it just kills it.
That's why I made elogind-usersv. It has the best of both worlds: it prevents login until the service manager reports ready (with PAM), it has a backend protocol similar to turnstile's for reporting ready and for graceful shutdown, and it relies on elogind for user session counting. It's service-manager agnostic, and only requires a simple backend.
Now the s6-frontend problem. Currently s6 --user command doesn't distinguish user paths from system paths, so s6-user is a temporary workaround to make it kinda usable. It's a thin wrapper that pins the user tree to persistent per-user paths and stops the s6 --user command from ever selecting the system /etc/s6/repo and system stores. It's non-resident: it normalizes HOME/XDG bases, reads its own TOML config, sets explicit repodir/bootdb/storelist, then execs the real s6. No supervision logic of its own. So s6-user is just like calling s6 --user, except it always addresses your per-user services instead of the system ones.
What I want from this
This is all work in progress(works on my machine though), and I'd love feedback and contributions, especially from people who know elogind/PAM and s6 internals. Bug reports, backend implementations for other service managers, testing on your own setup, all welcome.
The bigger goal behind these projects: make non-systemd distros able to run any software, even stuff that assumes systemd is there. The current milestone I'm working toward is getting the latest GNOME running on Artix with s6. If that interests you, or you've hit the same walls, get in touch or open an issue on the repos.