~hristoast/hristoast

hristoast/site/emacs-daemon-runit-service.html -rw-r--r-- 5.6 KiB View raw
85a97410Hristos N. Triantafillou Build on arch 3 days 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
<h1 id="title">Emacs daemon as a runit service</h1>

<div id="dates">
  <span>Posted: <time id="post-date">2018-06-09</time></span>
</div>

<p><span class="bold caps">Updated:</span> See <a href="/blog/emacs-daemon-runit-user-service/">this entry</a> on an Emacs daemon "user service" with runit!</p>

<p id="post-excerpt">
  So, you want to run an Emacs daemon as a runit service - and you also want to connect to it in your desktop session.  Thanks to the new <code>--fg-daemon</code> option in Emacs 26.x you now can!  I'm going to describe how to set up the service, as well as <code>sudo</code> rules for managing it without requiring a password each time.  Read on for the exciting details!
</p>

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

<h4 id="requirements"><a style="color: #222; text-decoration: none;" href="#requirements">Requirements</a></h4>

<p>Before you get too excited, there's a few prerequisites you'll need for this to be possible:</p>

<ul>
  <li>Emacs 26+:  As I've already mentioned, the <code>--fg-daemon</code> option was just added in Emacs 26 so you'll need that version.</li>
  <li>Runit:  It doesn't have to be your PID1 (but maybe it should be?), but you of course need it running, doing its thing.</li>
</ul>

I'll also go into detail about how to configure <code>sudo</code> as well as hotkeys for OpenBox.

<h4 id="the-service"><a style="color: #222; text-decoration: none;" href="#the-service">The Service</a></h4>

<p>The service "run" file is below:</p>

<pre><code>#!/bin/sh
export HOME=/home/hristos
cd $HOME
exec chpst -u hristos:hristos /usr/bin/emacs --fg-daemon=hristos-emacsd 2>&1</code></pre>

<p>Nothing too crazy for a runit service here.  I export my user's home directory as <code>$HOME</code>, this way Emacs can find my <code>~/.emacs.d/</code> directory.  I'm also naming the server's socket -- this way I can just pass that name to <code>emacsclient</code> when I want to attatch:</p>

<pre><code>$ emacsclient --socket-name=hristos-emacsd -c -n</code></pre>

<p>This is nicer than having to give the path to the server's socket; easier for a human to reason about.</p>

<h4 id="optional-logging"><a style="color: #222; text-decoration: none;" href="#optional-logging">Optional Logging</a></h4>

<p>This is optional, but I prefer to add logging to all runit services.  Doing this is standard fare for a runit service; Create a direcory called "log" in the root of your "emacs-daemon" service directory, and within that put a file called "run" with the below contents:</p>

<pre><code>#!/bin/sh
exec logger -t emacs-daemon</code></pre>

<p>Make sure you have something like <code>rsyslog</code> installed, and then you'll be able to find your "emacs-daemon" service logs in <code>/var/log/syslog</code> or wherever your logs go.  You can of course look at this output in the <code>*Messages*</code> buffer, but what the hay am I right?</p>

<h4 id="run-it"><a style="color: #222; text-decoration: none;" href="#run-it">Run It</a></h4>

<p>Now's the time to enable the service so that it can be used:</p>

<pre><code># ln -s /path/to/emacs-daemon /var/service/</code></pre>

<p>Alter the paths to match where your things actually are, and then that's it.  The Emacs daemon is now running.</p>

<h4 id="connecting"><a style="color: #222; text-decoration: none;" href="#connecting">Connecting</a></h4>

<p>As I showed above, you can now connect with a simple invocation of <code>emacsclient</code>, but some aliases would be a lot better.  For fish, I use this function:</p>

<pre><code>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>Now, anytime I invoke <code>emacs</code> from the command line, I'll attach to the daemon.  If it isn't running (and if you have zenity installed), then a message will pop up saying it was unable to connect.  And for you OpenBox users out there, add the following in your <code>rc.xml</code>:</p>

<pre><code>    &lt;keybind key="W-e"&gt;
      &lt;action name="Execute"&gt;
        &lt;startupnotify&gt;
          &lt;enabled&gt;true&lt;/enabled&gt;
          &lt;name&gt;Emacs&lt;/name&gt;
        &lt;/startupnotify&gt;
        &lt;command&gt;fish -c "emacs"&lt;/command&gt;
      &lt;/action&gt;
    &lt;/keybind&gt;</code></pre>

<p>Now you can open Emacs, and connect to your daemon with a simple press of "Meta+E"!</p>

<h4 id="sudo-rules"><a style="color: #222; text-decoration: none;" href="#sudo-rules">Sudo Rules</a></h4>

<p>Although it's actually simple to close the daemon from within Emacs itself, thus prompting runit to relaunch a new process, it's still great to be able to use <code>sv</code> to manage the service if need be.  Even better, you can use sudo rules to allow you to do this without needing a password.  Put the following in <code>/etc/sudoers.d/emacs-daemon</code>:</p>

<pre><code>Cmnd_Alias EMACSD_CMDS=/usr/bin/sv check emacs-daemon,/usr/bin/sv start emacs-daemon,/usr/bin/sv stop emacs-daemon,/usr/bin/sv restart emacs-daemon
hristos ALL=(ALL) NOPASSWD: EMACSD_CMDS</code></pre>

<p>Of course replace user names and commands as needed, but that's all you need.</p>

<h4 id="conclusion"><a style="color: #222; text-decoration: none;" href="#conclusion">Conclusion</a></h4>

<p>For a long time I managed an Emacs daemon outside of runit (or any other service manager) and it was fine; One can run <code>emacsclient</code> with the <code>--alternative-editor=''</code> option and that will start the daemon if it's not already running.  But having it start with your system, and having simple system-level controls for it is pretty useful and worthwhile considering the small amounts of effort required to implement.</p>