A while back, I wrote about setting up a runit service for an Emacs daemon. The idea behind that post was that you'd have a system-level service for your user Emacs session. But what if you want a "user service", like what systemd-using folks have? Read on to find out how to replicate this with runit!
First off, what even is a user service? As a reference, see this piece by Bozhidar Batsov about running Emacs with systemd's version of user services. With runit, it's simply a
runsvdir that your user can write to. runsvdir - starts and monitors a collection of runsv(8) processes Does runit support user-specific services?
Before you can have a user service for your Emacs daemon, you've got to have a service for your user services! This is because runit has no specific notion of user versus system services. So if you want a user to be able to easily manage some services, simply give them their own
/etc/sv/hristos-runsvdir/run file for that looks like this:
#!/bin/sh user=hristos exec 2>&1 exec chpst -u $user runsvdir /home/$user/.local/sv
Enable that, and now your user can write to
$HOME/.local/sv as a service directory. It's also possible to enable logging for this or any child services, if desired.
The "user service" file (
/home/hristos/.local/sv/emacs-daemon/run) doesn't look much different than the system-wide version:
#!/bin/sh export USER=hristos export HOME=/home/$USER export PATH=$HOME/.local/bin:$PATH # .. any other variables you need can go here .. cd $HOME exec /usr/bin/emacs --fg-daemon=$USER-emacsd
The most noteable change here is that the command no longer uses
chpst to run as a certain user, and the trailing output redirection (
2>&1) is also omitted due to that being handled by the parent "user service" service as described above.
As before, I'm using some fish functions to simplify interracting with services:
# A shortcut function for interacting with user services: function usv env SVDIR=$HOME/.local/sv sv $argv end # A shortcut function for launching an Emacs client process that connects to my daemon: function emacs command emacsclient --socket-name=hristos-emacsd -c -n $argv ; or \ zenity --error --no-wrap --text 'Failed to connect to the Emacs daemon!' ^/dev/null end
I call that
emacs function externally like this:
fish -c "emacs".
The method described above, utilizing "user services", is a bit better because it doesn't require any kind of privilege escalation outside of enabling the initial
runsvdir. But can you use a system-level service without such escalation?
It turns out it is indeed also possible to have an Emacs daemon at the system-level but not require
sudo or other privilege elevation methods. That's definitely worth checking out if a "user service" isn't something you need. Is it possible to allow a user other than root to control a service
There you have it, "user services" for runit and an Emacs daemon service for it. Is it one-to-one, the same as in systemd-land? No, but it is close enough where it matters and allows quite a bit of flexibility. Happy daemon-ing!