Subject: bug#16507: [RFC] Add a systemd service file for dealing with emacs --daemon.

From: [email-masked]
Date: Wed, 03 Dec 2014 22:16:45 +0100

Rüdiger Sonderfeld <[email-masked]> writes:

> As discussed in Bug#16507, I've added a systemd service file to deal with 
> emacs --daemon.  This however requires some installation changes.  That's why 
> I submit this patch for review before pushing it.
>
> A new configuration flag `--with-systemduserunitdir' is added to set the 
> installation directory for the user unit.  If it is unset an attempt is made 
> to locate the default directory by using pkg-config.
>
> (I guess this should also get an entry in etc/NEWS.)
>
> * configure.ac (with_systemduserunitdir): New option.
> * Makefile.in (systemdunitdir,SYSTEMD_UNITS): New variables.
> (install-etc): Install systemd unit file.
> (uninstall): Uninstall systemd unit file.
> * etc/emacs.service.in: New file.
> ---
>  ChangeLog            |  8 ++++++++
>  Makefile.in          | 17 +++++++++++++++++
>  configure.ac         | 19 +++++++++++++++++++
>  etc/ChangeLog        |  5 +++++
>  etc/emacs.service.in | 14 ++++++++++++++
>  5 files changed, 63 insertions(+)
>  create mode 100644 etc/emacs.service.in
>
> diff --git a/ChangeLog b/ChangeLog
> index cd7698c..05ad878 100644
> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,3 +1,11 @@
> +2014-12-03  Rüdiger Sonderfeld  <[email-masked]>
> +
> +	Add a systemd service file for dealing with emacs --daemon.
> +	* configure.ac (with_systemduserunitdir): New option.
> +	* Makefile.in (systemdunitdir,SYSTEMD_UNITS): New variables.
> +	(install-etc): Install systemd unit file.
> +	(uninstall): Uninstall systemd unit file.
> +
>  2014-12-01  Lars Magne Ingebrigtsen  <[email-masked]>
>  
>  	* .gitignore: Ignore loaddefs directly under lisp, and in
> diff --git a/Makefile.in b/Makefile.in
> index ccb70a4..b1e6be5 100644
> --- a/Makefile.in
> +++ b/Makefile.in
> @@ -241,6 +241,9 @@ etcdocdir=@etcdocdir@
>  # Where to install Emacs game score files.
>  gamedir=@gamedir@
>  
> +# Where to install systemd unit files.
> +systemdunitdir=@systemdunitdir@
> +
>  # ==================== Utility Programs for the Build ====================
>  
>  # Allow the user to specify the install program.
> @@ -286,6 +289,9 @@ SUBDIR_MAKEFILES = `echo $(SUBDIR_MAKEFILES_IN:.in=) | sed 
> 's|$(srcdir)/||g'`
>  COPYDIR = ${srcdir}/etc ${srcdir}/lisp
>  COPYDESTS = "$(DESTDIR)${etcdir}" "$(DESTDIR)${lispdir}"
>  
> +# systemd unit
> +SYSTEMD_UNITS = @SYSTEMD_UNITS@
> +
>  all: ${SUBDIR} info
>  
>  .PHONY: all ${SUBDIR} blessmail epaths-force epaths-force-w32 etc-emacsver
> @@ -716,6 +722,16 @@ install-etc:
>  	    || exit 1; \
>  	  done ; \
>  	done
> +	if test "x$(SYSTEMD_UNITS)" = "xemacs.service" ; then \
> +	  tmp=etc/emacs.service; rm -f $${tmp}; \
> +	  sed \
> +            -e "s;@emacs_prog@;${bindir}/${EMACSFULL};" \
> +	    -e "s;@emacsclient_prog@;${bindir}/emacsclient${EXEEXT};" \
> +	    "$(srcdir)/etc/emacs.service.in" > $${tmp}; \
> +	  umask 022; $(MKDIR_P) "$(DESTDIR)$(systemdunitdir)"; \
> +	  $(INSTALL_DATA) $${tmp} "$(DESTDIR)$(systemdunitdir)/emacs.service"; \
> +	  rm -f $${tmp}; \
> +	fi
>  
>  ### Build Emacs and install it, stripping binaries while installing them.
>  install-strip:
> @@ -771,6 +787,7 @@ uninstall: uninstall-$(NTDIR) uninstall-doc
>  	  file="$(DESTDIR)${gamedir}/$${file}"; \
>  	  [ -s "$${file}" ] || rm -f "$$file"; \
>  	done
> +	-rm -f "$(DESTDIR)$(systemdunitdir)/emacs.service"
>  
>  ### Windows-specific uninstall target for removing programs produced
>  ### in nt/, and its Posix do-nothing shadow.
> diff --git a/configure.ac b/configure.ac
> index 010abc8..e737f1b 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -374,6 +374,10 @@ otherwise for the first of `gfile' or `inotify' that is 
> usable.])
>   ],
>   [with_file_notification=$with_features])
>  
> +AC_ARG_WITH([systemduserunitdir],
> + AS_HELP_STRING([--with-systemduserunitdir=DIR], [Directory for systemd user 
> service files]),
> + [], [with_systemduserunitdir=default])
> +
>  ## For the times when you want to build Emacs but don't have
>  ## a suitable makeinfo, and can live without the manuals.
>  dnl http://lists.gnu.org/archive/html/emacs-devel/2008-04/msg01844.html@@ -2678,6 +2682,21 @@ AC_SUBST(NOTIFY_OBJ)
>  AC_SUBST(GFILENOTIFY_CFLAGS)
>  AC_SUBST(GFILENOTIFY_LIBS)
>  
> +if test "x$with_systemduserunitdir" != xno; then
> +  if test "x$with_systemduserunitdir" = xdefault; then
> +    with_systemduserunitdir=`"$PKG_CONFIG" --variable=systemduserunitdir 
> systemd`
> +  fi
> +  AC_SUBST([systemdunitdir], [$with_systemduserunitdir])
> +fi
> +
> +if test -n "$with_systemduserunitdir" -a "x$with_systemduserunitdir" != xno ; 
> then
> +  SYSTEMD_UNITS="emacs.service"
> +else
> +  SYSTEMD_UNITS=""
> +fi
> +
> +AC_SUBST(SYSTEMD_UNITS)
> +
>  dnl Do not put whitespace before the #include statements below.
>  dnl Older compilers (eg sunos4 cc) choke on it.
>  HAVE_XAW3D=no
> diff --git a/etc/ChangeLog b/etc/ChangeLog
> index 4f672df..02c0895 100644
> --- a/etc/ChangeLog
> +++ b/etc/ChangeLog
> @@ -1,3 +1,8 @@
> +2014-12-03  Rüdiger Sonderfeld  <[email-masked]>
> +
> +	Add a systemd service file for dealing with emacs --daemon.
> +	* emacs.service.in: New file.
> +
>  2014-12-02  Eli Zaretskii  <[email-masked]>
>  
>  	* NEWS: Mention 'bidi-find-overridden-directionality'.
> diff --git a/etc/emacs.service.in b/etc/emacs.service.in
> new file mode 100644
> index 0000000..0e59bc2
> --- /dev/null
> +++ b/etc/emacs.service.in
> @@ -0,0 +1,14 @@
> +# -*- conf-mode -*-
> +# Copyright (C) 2014 Free Software Foundation, Inc.
> +[Unit]
> +Description=Emacs: the extensible, customizable text editor - and more.
> +Documentation=info:Emacs man:emacs(1) https://gnu.org/software/emacs/+
> +[Service]
> +Type=forking
> +ExecStart=@emacs_prog@ --daemon
> +ExecStop=@emacsclient_prog@ --eval "(kill-emacs)"
> +Restart=on-failure
> +
> +[Install]
> +WantedBy=default.target

I have a unit file that enables ssh-agent, which is otherwise a problem.
I'm not sure if its generally usable.

[Unit]
Description=Emacs: the extensible, self-documenting text editor

[Service]
Type=forking
ExecStart=/usr/bin/ssh-agent /usr/local/bin/emacs --daemon
ExecStop=/usr/local/bin/emacs --eval "(progn (setq kill-emacs-hook 'nil) (kill-emacs))"
Restart=always
User=%i
WorkingDirectory=%h

[Install]
WantedBy=multi-user.target

The corresponding elisp looks like (warning, lame hard-coding):

(defun ssh-agent-init ()
  (interactive)
  (save-excursion
    (if (get-buffer "ssh-agent-process") (kill-buffer "ssh-agent-process" ))

    (with-current-buffer     (get-buffer-create "ssh-agent-process")
      (call-process "ssh-agent" nil t t  "-c" "-a" "/home/joakim/.ssh-agent-sock")

      (goto-char (point-min))

      (message "buf: %s cont: %s"(current-buffer) (buffer-string))

      (search-forward-regexp ".* .* \\(.*\\);")
      (message "1: %s" (match-string 0)(match-string 1))
      (setenv "SSH_AUTH_SOCK" (match-string 1))
      (setq ssh-auth-sock (getenv "SSH_AUTH_SOCK" ))
      (message "%s" (getenv "SSH_AUTH_SOCK" )))
    )
  )

(setenv "SSH_AUTH_SOCK" "/home/joakim/.ssh-agent-sock")

;;from the internetz
;; - it hangs, but works anyway
;; - it should also run ssh-agent-init intelligently

(defun ssh-add-process-filter (process string)
  (save-match-data
    (if (string-match ":\\s *\\'" string)
        (process-send-string process (concat (read-passwd string) "\n"))
      (message "%s" string))))
(defun ssh-add ()
  "Run ssh-add to add a key to the running SSH agent.
Let Emacs prompt for the passphrase."
(interactive)
  (let ((process-connection-type t)
            process)
    (unwind-protect
        (progn
          (setq process (start-process "ssh-add" nil
                                       "ssh-add" ))
          (set-process-filter process 'ssh-add-process-filter)
          (while (accept-process-output process)))
      (if (eq (process-status process) 'run)
          (kill-process process)))))

-- 
Joakim Verona