Hi, This patch adds a command-line switch to urxvtd to enable support for systemd socket activation. The purpose of the change is to allow configuring urxvtd as a systemd service which starts on demand. Most Linux distros are using systemd these days so it is widely applicable.
The patch is against latest CVS. The changes have been tested against the latest stable release, 9.22, running under NixOS 18.09. Please see the diffs for doc/rxvtd.1.pod and doc/systemd for an explanation of how it works. For a primer on systemd socket activation, see http://0pointer.de/blog/projects/socket-activation.html. An existing solution to on-demand activation is the urxvtc wrapper script provided by the urxvtc manpage. For systems that run urxvtd as a systemd service, this script could be adapted as follows: #!/bin/sh urxvtc "$@" if [ $? -eq 2 ]; then systemctl --user start urxvtd.service urxvtc "$@" fi I feel the socket activation approach is preferable for the sake of consistency on these systems. Other similar on-demand services are likely to be using socket activation, so the user will expect urxvtd to be configured this way. (As an admin I'd find it easier to remember that services A, B, and C are socket activated, than that A and C are socket-activated whereas B has a custom wrapper script.) In addition, since systemctl exits as soon as the service daemon is launched, it seems possible (if unlikely) to have a race condition where the second urxvtc invocation occurs before urxvtd has created its socket, leading to failure. Thanks for your consideration. Cheers, Jacob (fishyfriend) --- config.h.in | 4 +++ configure.ac | 20 +++++++++++++ doc/rxvtd.1.pod | 16 ++++++++++ doc/systemd/README.systemd | 25 ++++++++++++++++ doc/systemd/urxvtd.service | 8 +++++ doc/systemd/urxvtd.socket | 8 +++++ src/rxvtd.C | 61 ++++++++++++++++++++++++++++++++++++-- 7 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 doc/systemd/README.systemd create mode 100644 doc/systemd/urxvtd.service create mode 100644 doc/systemd/urxvtd.socket diff --git a/config.h.in b/config.h.in index 914d6062..3ff46a1c 100644 --- a/config.h.in +++ b/config.h.in @@ -15,6 +15,10 @@ /* Define if you want bold and italic support */ #undef ENABLE_STYLES +/* Define if you want to enable a command-line option for systemd socket + activation */ +#undef ENABLE_SYSTEMD + /* Define if you want your background to use the parent window background */ #undef ENABLE_TRANSPARENCY diff --git a/configure.ac b/configure.ac index 0da3b596..4e23c898 100644 --- a/configure.ac +++ b/configure.ac @@ -97,6 +97,7 @@ support_8bitctrls=no support_iso14755=yes support_styles=yes support_perl=yes +support_systemd=no codesets=all dnl# -------------------------------------------------------------------------- @@ -133,6 +134,7 @@ AC_ARG_ENABLE(everything, support_iso14755=no support_styles=no support_perl=no + support_systemd=no codesets= fi if test x$enableval = xyes; then @@ -161,6 +163,7 @@ AC_ARG_ENABLE(everything, support_iso14755=yes support_styles=yes support_perl=yes + support_systemd=yes codesets=all fi ]) @@ -413,6 +416,12 @@ AC_ARG_WITH(terminfo, AC_DEFINE_UNQUOTED(RXVT_TERMINFO, "$withval", Set TERMINFO value to the value given by configure) terminfo="$withval" fi]) +AC_ARG_ENABLE(systemd, + [ --enable-systemd enable systemd socket activation], + [if test x$enableval = xyes -o x$enableval = xno; then + support_systemd=$enableval + fi]) + if test x$support_resources = xno; then if test x$support_frills = xyes || test x$support_perl = xyes; then AC_MSG_ERROR([--disable-resources requires --disable-frills --disable-perl]) @@ -481,6 +490,10 @@ AC_CHECK_HEADERS( \ wchar.h \ ) +if test x$support_systemd = xyes; then + AC_CHECK_HEADER(systemd/sd-daemon.h) +fi + AC_CACHE_CHECK([for XLIB_ILLEGAL_ACCESS], rxvt_cv_xlib_illegal_access, [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([ @@ -582,6 +595,13 @@ TTY_GROUP_CHECK dnl# -------------------------------------------------------------------------- dnl# now add and remove other stuff dnl# -------------------------------------------------------------------------- +if test x$support_systemd = xyes; then + RXVT_CHECK_MODULES(SYSTEMD, systemd, [ + LIBS="$LIBS -lsystemd" + ], [AC_MSG_ERROR(systemd not found)]) + AC_DEFINE(ENABLE_SYSTEMD, 1, Define if you want to enable a command-line option for systemd socket activation) +fi + support_image=no if test x$support_inheritpixmap = xyes || test x$support_pixbuf = xyes; then support_image=yes diff --git a/doc/rxvtd.1.pod b/doc/rxvtd.1.pod index 08d6b2b6..56bbe2b8 100644 --- a/doc/rxvtd.1.pod +++ b/doc/rxvtd.1.pod @@ -81,6 +81,22 @@ listening sockets for additional protocols. The code is currently executed I<before> creating the normal listening sockets: this might change in future versions. +=item B<-a>, B<--activate> + +Support systemd socket activation (requires systemd support to be enabled +when compiling B<@@RXVT_NAME@@d>). + +This option causes urxvtd to check on startup whether systemd passed in a +listening socket. If such a socket is found, urxvtd will use that socket instead +of creating its own. Otherwise, it will fall back to creating a new socket +as normal. + +Note that the filesystem path used by systemd for the socket should match +the value of I<RXVT_SOCKET> in the user environment (or the default socket +path if I<RXVT_SOCKET> is unset; see "ENVIRONMENT" below). This is to +ensure that B<@@RXVT_NAME@@c> can find the daemon. See I<doc/systemd> +for more information about how to configure urxvtd as a systemd service. + =back =head1 EXAMPLES diff --git a/doc/systemd/README.systemd b/doc/systemd/README.systemd new file mode 100644 index 00000000..1fcd345c --- /dev/null +++ b/doc/systemd/README.systemd @@ -0,0 +1,25 @@ +README for systemd support +-------------------------- + +rxvt-unicode includes support for running the terminal daemon (urxvtd) as a +socket-activated service under systemd. To enable socket activation, build +rxvt-unicode with the "--with-systemd" configure flag and invoke urxvtd with +the "--activate"/"-a" command line option. (Consult the man page for more +details regarding the behavior of this option.) + +You will also need to set up socket and service unit files for urxvtd. For most +systemd setups, it should suffice to copy the example unit files in this +directory into /etc/systemd/user after applying any customizations for your +particular situation. Then run: + + systemctl --user enable --now urxvtd.socket + +Finally, be sure that RXVT_SOCKET is set correctly in the environment of each +user who will run urxvtc. The example unit files use the path string +"%t/urxvtd-socket"; for user services, this evaluates to +"$XDG_RUNTIME_DIR/urxvt-socket". Thus, in your user's shell profile, you could +include the line + + export RXVT_SOCKET="$XDG_RUNTIME_DIR/urxvt-socket" + +to ensure that urxvtc can find the daemon. diff --git a/doc/systemd/urxvtd.service b/doc/systemd/urxvtd.service new file mode 100644 index 00000000..a62bcf48 --- /dev/null +++ b/doc/systemd/urxvtd.service @@ -0,0 +1,8 @@ +[Unit] +Description=urxvt terminal daemon + +[Service] +Environment=RXVT_SOCKET=%t/urxvtd-socket +ExecStart=/usr/bin/urxvtd -o -a +Restart=on-failure +RestartSec=5s diff --git a/doc/systemd/urxvtd.socket b/doc/systemd/urxvtd.socket new file mode 100644 index 00000000..d6b61f9a --- /dev/null +++ b/doc/systemd/urxvtd.socket @@ -0,0 +1,8 @@ +[Unit] +Description=socket for urxvtd, the urxvt terminal daemon + +[Socket] +ListenStream=%t/urxvtd-socket + +[Install] +WantedBy=graphical-session.target diff --git a/src/rxvtd.C b/src/rxvtd.C index 50261c62..dc225c9c 100644 --- a/src/rxvtd.C +++ b/src/rxvtd.C @@ -41,6 +41,10 @@ # include <sys/mman.h> #endif +#if ENABLE_SYSTEMD +#include <systemd/sd-daemon.h> +#endif + #include <errno.h> #include "rxvt.h" @@ -75,7 +79,14 @@ struct unix_listener { void accept_cb (ev::io &w, int revents); ev::io accept_ev; + // create listener on a new socket unix_listener (const char *sockname); + + // create listener on an existing socket + unix_listener (int descriptor); + + // copy constructor + unix_listener (const unix_listener &other); }; unix_listener::unix_listener (const char *sockname) @@ -123,6 +134,23 @@ unix_listener::unix_listener (const char *sockname) accept_ev.start (fd, ev::READ); } +unix_listener::unix_listener (int descriptor) +{ + accept_ev.set<unix_listener, &unix_listener::accept_cb> (this); + + fd = descriptor; + + fcntl (fd, F_SETFD, FD_CLOEXEC); + fcntl (fd, F_SETFL, O_NONBLOCK); + + accept_ev.start (fd, ev::READ); +} + +unix_listener::unix_listener (const unix_listener &other) +{ + fd = other.fd; +} + void unix_listener::accept_cb (ev::io &w, int revents) { int fd2 = accept (fd, 0, 0); @@ -236,6 +264,9 @@ main (int argc, char *argv[]) #if ENABLE_MLOCK static char opt_lock; #endif +#if ENABLE_SYSTEMD + static char opt_activate; +#endif for (int i = 1; i < argc; i++) { @@ -252,6 +283,10 @@ main (int argc, char *argv[]) #if ENABLE_PERL else if (!strcmp (argv [i], "-e") || !strcmp (argv [i], "--eval")) opt_eval = argv [++i]; +#endif +#if ENABLE_SYSTEMD + else if (!strcmp (argv [i], "-a") || !strcmp (argv [i], "--activate")) + opt_activate = 1; #endif else { @@ -276,13 +311,35 @@ main (int argc, char *argv[]) displays.get (dpy ? dpy : ":0"); // move string logic into rxvt_display maybe? char *sockname = rxvt_connection::unix_sockname (); - unix_listener l (sockname); + char supplied_fd = 0; + +#if ENABLE_SYSTEMD + // optionally look for a socket file passed in by systemd. + if (opt_activate) + { + int n = sd_listen_fds (1); + if (n > 1) + { + fputs ("too many file descriptors received, aborting.\n", stderr); + exit (EXIT_FAILURE); + } + else if (n == 1) + supplied_fd = SD_LISTEN_FDS_START + 0; + } +#endif + + unix_listener l = supplied_fd ? + unix_listener (supplied_fd) : + unix_listener (sockname); chdir ("/"); if (!opt_quiet) { - printf ("rxvt-unicode daemon listening on %s.\n", sockname); + if (supplied_fd) + puts ("rxvt-unicode daemon listening on received socket."); + else + printf ("rxvt-unicode daemon listening on %s.\n", sockname); fflush (stdout); } -- 2.18.1 _______________________________________________ rxvt-unicode mailing list [email protected] http://lists.schmorp.de/mailman/listinfo/rxvt-unicode
