~hristoast/hristoast

hristoast/site/blog/emacs-daemon-runit-user-service.html -rw-r--r-- 4.2 KiB
d767d97cHristos N. Triantafillou A regex, to get both indexes an hour ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<h1 id="title">Emacs daemon as a runit "user service"</h1>

<div id="dates">
  <span>Posted: <time id="post-date">2020-07-30</time></span>
</div>

<p id="post-excerpt">
  A while back, <a href="/blog/emacs-daemon-runit-service/">I wrote about</a> 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!
</p>

<div id="toc"></div>

<h3>What Is A User Service?</h3>

<p>
  First off, what even is a user service? As a reference, see <a href="https://emacsredux.com/blog/2020/07/16/running-emacs-with-systemd/">this piece by Bozhidar Batsov</a> about running Emacs with systemd's version of user services. With runit, it's simply a <code>runsvdir</code> that your user can write to. <span class="footnote"> <a href="http://smarden.org/runit/runsvdir.8.html">runsvdir - starts and monitors a collection of runsv(8) processes</a></span> <span class="footnote"> <a href="http://smarden.org/runit/faq.html#userservices">Does runit support user-specific services?</a></span>
</p>

<h3>Your User's Runsvdir</h3>

<p>
  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 <code>runsvdir</code>.
</p>

<p>
  The <code>/etc/sv/hristos-runsvdir/run</code> file for that looks like this:
</p>

<pre><code class="language-sh">#!/bin/sh
user=hristos
exec 2>&1
exec chpst -u $user runsvdir /home/$user/.local/sv</code></pre>

<p>
  Enable that, and now your user can write to <code>$HOME/.local/sv</code> as a service directory. It's also possible to enable logging for this or any child services, if desired.
</p>

<h3>The Emacs Daemon User Service</h3>

<p>
  The "user service" file (<code>/home/hristos/.local/sv/emacs-daemon/run</code>) doesn't look much different than the system-wide version:
</p>

<pre><code class="language-sh">#!/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</code></pre>

<p>
  The most noteable change here is that the command no longer uses <code>chpst</code> to run as a certain user, and the trailing output redirection (<code>2>&1</code>) is also omitted due to that being handled by the parent "user service" service as described above.
</p>

<h3>Functions/Shortcuts</h3>

<p>
  As before, I'm using some fish functions to simplify interracting with services:
</p>

<pre><code class="language-fish"># 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</code></pre>

<p>
  I call that <code>emacs</code> function externally like this: <code>fish -c "emacs"</code>.
</p>

<h3>Sudo Rules?</h3>

<p>
  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 <code>runsvdir</code>.  But can you use a system-level service without such escalation?
</p>

<p>
  It turns out it is indeed also possible to have an Emacs daemon at the system-level but not require <code>sudo</code> or other privilege elevation methods. That's definitely worth checking out if a "user service" isn't something you need. <span class="footnote"> <a href="http://smarden.org/runit/faq.html#user">Is it possible to allow a user other than root to control a service</a></span>
</p>

<h3>Conclusion</h3>

<p>
  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!
</p>

<h3>Footnotes And References</h3>

<div id="footnotes"></div>