From 1775d9857a7ac60578f3560613ead7c189d8b756 Mon Sep 17 00:00:00 2001 From: Julien Moutinho Date: Wed, 16 Mar 2022 02:43:18 +0100 Subject: [PATCH] Add support for systemd socket activation See http://0pointer.de/blog/projects/socket-activation.html and https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html Fixes #3117 --- Makefile.am | 5 ++++ compat.h | 5 ++++ compat/systemd.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 24 +++++++++++++++++++ server.c | 22 +++++++++++------- tmux.c | 1 + tmux.h | 2 ++ 7 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 compat/systemd.c diff --git a/Makefile.am b/Makefile.am index 68494932..5bdd9d5f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -204,6 +204,11 @@ if NEED_FORKPTY nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c endif +# Add compat file for systemd. +if HAVE_SYSTEMD +nodist_tmux_SOURCES += compat/systemd.c +endif + # Add compat file for utf8proc. if HAVE_UTF8PROC nodist_tmux_SOURCES += compat/utf8proc.c diff --git a/compat.h b/compat.h index be726831..6eb97619 100644 --- a/compat.h +++ b/compat.h @@ -421,6 +421,11 @@ void *reallocarray(void *, size_t, size_t); void *recallocarray(void *, size_t, size_t, size_t); #endif +#ifdef HAVE_SYSTEMD +/* systemd.c */ +int systemd_create_socket(int, char **); +#endif + #ifdef HAVE_UTF8PROC /* utf8proc.c */ int utf8proc_wcwidth(wchar_t); diff --git a/compat/systemd.c b/compat/systemd.c new file mode 100644 index 00000000..8e34c007 --- /dev/null +++ b/compat/systemd.c @@ -0,0 +1,60 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2022 Nicholas Marriott + * Copyright (c) 2022 Julien Moutinho + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include + +#include "tmux.h" + +int +systemd_create_socket(int flags, char **cause) +{ + int fds; + int fd; + struct sockaddr_un sa; + int addrlen = sizeof sa; + + fds = sd_listen_fds(0); + if (fds > 1) { /* too many file descriptors */ + errno = E2BIG; + goto fail; + } + + if (fds == 1) { /* socket-activated */ + fd = SD_LISTEN_FDS_START; + if (!sd_is_socket_unix(fd, SOCK_STREAM, 1, NULL, 0)) { + errno = EPFNOSUPPORT; + goto fail; + } + if (getsockname(fd, (struct sockaddr *)&sa, &addrlen) == -1) + goto fail; + socket_path = xstrdup(sa.sun_path); + socket_can_be_created_again = 0; + return (fd); + } + + return (server_create_socket(flags, cause)); + +fail: + if (cause != NULL) + xasprintf(cause, "systemd socket error (%s)", strerror(errno)); + return (-1); +} diff --git a/configure.ac b/configure.ac index e473f141..f90d9f05 100644 --- a/configure.ac +++ b/configure.ac @@ -390,6 +390,30 @@ if test "x$enable_utf8proc" = xyes; then fi AM_CONDITIONAL(HAVE_UTF8PROC, [test "x$enable_utf8proc" = xyes]) +# Check for systemd support. +AC_ARG_ENABLE( + systemd, + AS_HELP_STRING(--enable-systemd, enable systemd integration) +) +if test x"$enable_systemd" = xyes; then + PKG_CHECK_MODULES( + SYSTEMD, + libsystemd, + [ + AM_CPPFLAGS="$SYSTEMD_CFLAGS $AM_CPPFLAGS" + CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS" + LIBS="$SYSTEMD_LIBS $LIBS" + AC_DEFINE(HAVE_SYSTEMD) + found_systemd=yes + ], + found_systemd=no + ) + if test "x$found_systemd" = xno; then + AC_MSG_ERROR("systemd not found") + fi +fi +AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$found_systemd" = xyes]) + # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. AC_MSG_CHECKING(for b64_ntop) AC_LINK_IFELSE([AC_LANG_PROGRAM( diff --git a/server.c b/server.c index 2db5a8d8..5acddb10 100644 --- a/server.c +++ b/server.c @@ -100,7 +100,7 @@ server_check_marked(void) } /* Create server socket. */ -static int +int server_create_socket(int flags, char **cause) { struct sockaddr_un sa; @@ -214,7 +214,11 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base, gettimeofday(&start_time, NULL); +#ifdef HAVE_SYSTEMD + server_fd = systemd_create_socket(flags, &cause); +#else server_fd = server_create_socket(flags, &cause); +#endif if (server_fd != -1) server_update_socket(); if (~flags & CLIENT_NOFORK) @@ -424,14 +428,16 @@ server_signal(int sig) server_child_signal(); break; case SIGUSR1: - event_del(&server_ev_accept); - fd = server_create_socket(server_client_flags, NULL); - if (fd != -1) { - close(server_fd); - server_fd = fd; - server_update_socket(); + if (socket_can_be_created_again) { + event_del(&server_ev_accept); + fd = server_create_socket(server_client_flags, NULL); + if (fd != -1) { + close(server_fd); + server_fd = fd; + server_update_socket(); + } + server_add_accept(0); } - server_add_accept(0); break; case SIGUSR2: proc_toggle_log(server_proc); diff --git a/tmux.c b/tmux.c index 11c368ff..187a7429 100644 --- a/tmux.c +++ b/tmux.c @@ -40,6 +40,7 @@ struct environ *global_environ; struct timeval start_time; const char *socket_path; +int socket_can_be_created_again = 1; int ptm_fd = -1; const char *shell_command; diff --git a/tmux.h b/tmux.h index 370c7773..d5c63390 100644 --- a/tmux.h +++ b/tmux.h @@ -2001,6 +2001,7 @@ extern struct options *global_s_options; extern struct options *global_w_options; extern struct environ *global_environ; extern struct timeval start_time; +extern int socket_can_be_created_again; extern const char *socket_path; extern const char *shell_command; extern int ptm_fd; @@ -2583,6 +2584,7 @@ int server_start(struct tmuxproc *, int, struct event_base *, int, char *); void server_update_socket(void); void server_add_accept(int); void printflike(1, 2) server_add_message(const char *, ...); +int server_create_socket(int, char **); /* server-client.c */ RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp); -- 2.34.1