This is a quick post explaining how to use systemd to automatically load emacs at the startup of your operating system and then use emacs client to connect to it. This requires emacs version greater or equal to 23 and also a linux distro that is using systemd. In my system I am running Arch Linux with emacs 24.3 and at the time of this post I was using systemd version 212.
UPDATE 27/06/2013:This post explained how to have Emacs start as a general systemd service ran by root. Go to the end of the blogpost for an even better way to configure emacs as a user systemd service!
Step 1. Create the systemd service
First of all we need to create the systemd service file as is shown in the emacs wiki. Place the following into a file named
[Unit] Description=Emacs: the extensible, self-documenting text editor [Service] Type=forking ExecStart=/usr/bin/emacs --daemon ExecStop=/usr/bin/emacsclient --eval "(progn (setq kill-emacs-hook 'nil) (kill-emacs))" Restart=always User=%i WorkingDirectory=%h [Install] WantedBy=multi-user.target
In case you are wondering how systemd works you can visit the man page or the Arch Linux wiki page on the subject. The above should start your emacs in daemon mode at startup and restart it even if it’s killed. It will start by the user who enables/starts this service file and use his init file for startup.
To stop the emacs unit we use the
emacsclient to send some lisp code for evaluation. This code simply exits the process and stops the daemon.
(progn (setq kill-emacs-hook 'nil) (kill-emacs))
Step 2. Enable the service
With systemd you can among other things, enable, disable, start, stop or query a status of a service. We achieve all these by the following commands for emacs as a service.
~$ sudo systemctl enable email@example.com ~$ sudo systemctl disable firstname.lastname@example.org ~$ sudo systemctl start email@example.com ~$ sudo systemctl stop firstname.lastname@example.org ~$ systemctl status email@example.com
Please note that you should replace lefteris with your own user name. Also
.service can be ommited. It simply serves to determine the type of systemd unit we are referring to. Service is the default. Other units can be mountpoints, devices and sockets.
- enable: The service will start from statup next time you boot the system
- disable: Undo an enable
- start: Starts the unit using the execution start command
- start: Stops the unit using the execution stop command
- status: Returns a status report about the unit
I would suggest you enable the emacs systemd unit now using the above command. Then start it. You can also check the status of the unit and get output similar to the one below.
Step 3. Connect to the server using emacsclient
Now it should be pretty straight forward to connect to the running emacs daemon using emacsclient. For example running
emacsclient -c should connect you to the server.
emacsclient: connect: Connection refused emacsclient: No socket or alternate editor. Please use: --socket-name --server-file (or environment variable EMACS_SERVER_FILE) --alternate-editor (or environment variable ALTERNATE_EDITOR)
Wow! What’s this? But the server is indeed running. You can quickly check it with a
ps aux | grep emacs . And to add to that the owner of the process is our user and not the root user. So what is the problem?
We should also check if the server is indeed listening and on which socket by using the following command:
~$ sudo netstat -xaupen | grep emacs unix 2 [ ACC ] STREAM LISTENING 88697 5924/emacs /tmp/emacs1000/server
Hmm … the output looks all right but there is something weird about the socket. Usually sockets opened by user programs should be under
/tmp/USERNAME/... . That explains why emacsclient can’t connect. So all we have to do is alter the command a bit:
emacsclient -c --socket-name /tmp/emacs1000/server
And voila! This connects us to the correct emacs server instance.
I can’t say I am sure if this can be considered a bug of emacsclient, a bug of emacs in daemon mode or neither. In any case using the
--socket-name argument solves the problem and allows us to connect to emacs at any point in time having it started as a systemd unit at startup. If you have any comments or suggestions, especially concerning the socket argument please don’t hesitate to write below.
Until next time!
UPDATE 27/06/2013 – Configuring Emacs as a user systemd service
After working for some time with Emacs as a systemd service and learning more about systemd I realized that there is a better (and easier) way to configure emacs as a systemd service specified only for the user you need. Accomplishing this is really easy. Look at the following service file.
[Unit] Description=Emacs: the extensible, self-documenting text editor [Service] Type=forking ExecStart=/usr/bin/emacs --daemon ExecStop=/usr/bin/emacsclient --eval "(progn (setq kill-emacs-hook 'nil) (kill-emacs))" Restart=always # Remove the limit in startup timeout, since emacs # cloning and building all packages can take time TimeoutStartSec=0 [Install] WantedBy=default.target
The service file is almost the same as the one in the original post except for the fact that User and Working directory do not need to be specified. Moreover I have added
TimeoutStartSec=0 to avoid systemd killing emacs if for some reason it takes too long to start and send the
sd_notify message. This can happen if for example you are using el-get to clone and build all your Emacs packages in a clean environment.
Finally notice that multi-user target has been replaced by the default.target. If you are using some other –user systemd scripts you can configure that section properly. If you don’t know what a target is then just leave it as the default.target. In –user service files there is no multi-user.target so this is a field that you will need to change.
Now all that you need to do is copy this service file as
~/.config/systemd/user/emacs.service. After that you can work with it just as you did in the original blog post but with the main difference of having to add the
--user argument after systemctl. For example:
systemctl --user enable emacs systemctl --user start emacs systemctl --user stop emacs systemctl --user disable emacs