]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: mworker: get rid of libsystemd
authorWilliam Lallemand <wlallemand@haproxy.com>
Wed, 3 Apr 2024 13:13:00 +0000 (15:13 +0200)
committerWilliam Lallemand <wlallemand@haproxy.com>
Wed, 3 Apr 2024 13:53:18 +0000 (15:53 +0200)
Given the xz drama which allowed liblzma to be linked to openssh, lets remove
libsystemd to get rid of useless dependencies.

The sd_notify API seems to be stable and is now documented. This patch replaces
the sd_notify() and sd_notifyf() function by a reimplementation inspired by the
systemd documentation.

This should not change anything functionnally. The function will be built when
haproxy is built using USE_SYSTEMD=1.

References:
  https://github.com/systemd/systemd/issues/32028
  https://www.freedesktop.org/software/systemd/man/devel/sd_notify.html#Notes

Before:

wla@kikyo:~% ldd /usr/sbin/haproxy
linux-vdso.so.1 (0x00007ffcfaf65000)
libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x000074637fef4000)
libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x000074637fe4f000)
libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x000074637f400000)
liblua5.4.so.0 => /lib/x86_64-linux-gnu/liblua5.4.so.0 (0x000074637fe0d000)
libsystemd.so.0 => /lib/x86_64-linux-gnu/libsystemd.so.0 (0x000074637f92a000)
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x000074637f365000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000074637f000000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x000074637f27a000)
libcap.so.2 => /lib/x86_64-linux-gnu/libcap.so.2 (0x000074637fdff000)
libgcrypt.so.20 => /lib/x86_64-linux-gnu/libgcrypt.so.20 (0x000074637eeb8000)
liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x000074637fdcd000)
libzstd.so.1 => /lib/x86_64-linux-gnu/libzstd.so.1 (0x000074637ee01000)
liblz4.so.1 => /lib/x86_64-linux-gnu/liblz4.so.1 (0x000074637fda8000)
/lib64/ld-linux-x86-64.so.2 (0x000074637ff5d000)
libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x000074637f904000)

After:

wla@kikyo:~% ldd /usr/sbin/haproxy
linux-vdso.so.1 (0x00007ffd51901000)
libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f758d6c0000)
libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x00007f758d61b000)
libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x00007f758ca00000)
liblua5.4.so.0 => /lib/x86_64-linux-gnu/liblua5.4.so.0 (0x00007f758d5d9000)
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f758d365000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f758d5ba000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f758c600000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f758c915000)
/lib64/ld-linux-x86-64.so.2 (0x00007f758d729000)

A backport to all stable versions could be considered at some point.

Makefile
include/haproxy/systemd.h [new file with mode: 0644]
src/mworker.c
src/systemd.c [new file with mode: 0644]

index c904094dc45a7e55300711a63c35e597e6f27e37..df50d1700db7971adb0a96c58878783554df8555 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -734,7 +734,7 @@ ifneq ($(USE_WURFL),)
 endif
 
 ifneq ($(USE_SYSTEMD),)
-  SYSTEMD_LDFLAGS = -lsystemd
+  OPTIONS_OBJS    += src/systemd.o
 endif
 
 ifneq ($(USE_PCRE)$(USE_STATIC_PCRE)$(USE_PCRE_JIT),)
diff --git a/include/haproxy/systemd.h b/include/haproxy/systemd.h
new file mode 100644 (file)
index 0000000..65b0ab6
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _HAPROXY_SYSTEMD_H
+#define _HAPROXY_SYSTEMD_H
+
+int sd_notify(int unset_environment, const char *message);
+int sd_notifyf(int unset_environment, const char *format, ...);
+
+#endif
index be98246bf45f939ef0a8c73d938419eb3166b837..c4461cc10e8398069a6f04475438e28084c798ec 100644 (file)
 #include <sys/wait.h>
 #include <unistd.h>
 
-#if defined(USE_SYSTEMD)
-#include <systemd/sd-daemon.h>
-#endif
-
 #include <haproxy/api.h>
 #include <haproxy/cfgparse.h>
 #include <haproxy/cli.h>
@@ -45,6 +41,9 @@
 #include <haproxy/tools.h>
 #include <haproxy/version.h>
 
+#if defined(USE_SYSTEMD)
+#include <haproxy/systemd.h>
+#endif
 
 static int exitcode = -1;
 static int max_reloads = -1; /* number max of reloads a worker can have until they are killed */
diff --git a/src/systemd.c b/src/systemd.c
new file mode 100644 (file)
index 0000000..fb36dd9
--- /dev/null
@@ -0,0 +1,134 @@
+/* SPDX-License-Identifier: MIT-0 */
+
+/* Implement the systemd notify protocol without external dependencies.
+ * Supports both readiness notification on startup and on reloading,
+ * according to the protocol defined at:
+ * https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html
+ * This protocol is guaranteed to be stable as per:
+ * https://systemd.io/PORTABILITY_AND_STABILITY/
+ *
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <haproxy/tools.h>
+
+/*
+ *  standalone reimplementation of sd_notify from the libsystemd
+ *  Return:
+ *     -errno in case of error
+ *     0 when ignored
+ *     >0 when succeeded
+ *
+ * Will send <message> over the NOTIFY_SOCKET.
+ * When unset_environement is set, unsetenv NOTIFY_SOCKET.
+ */
+int sd_notify(int unset_environment, const char *message)
+{
+       union sockaddr_union {
+               struct sockaddr sa;
+               struct sockaddr_un sun;
+       } socket_addr = {
+               .sun.sun_family = AF_UNIX,
+       };
+       int ret = 1;
+       int fd = -1;
+       size_t path_length, message_length;
+       const char *socket_path;
+       ssize_t written;
+
+       socket_path = getenv("NOTIFY_SOCKET");
+       if (!socket_path) {
+               ret = 0; /* Not running under systemd? Nothing to do */
+               goto end;
+       }
+
+       if (unset_environment)
+               unsetenv("NOTIFY_SOCKET");
+
+       if (!message) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       message_length = strlen(message);
+       if (message_length == 0) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Only AF_UNIX is supported, with path or abstract sockets */
+       if (socket_path[0] != '/' && socket_path[0] != '@') {
+               ret = -EAFNOSUPPORT;
+               goto end;
+       }
+
+       path_length = strlen(socket_path);
+       /* Ensure there is room for NUL byte */
+       if (path_length >= sizeof(socket_addr.sun.sun_path)) {
+               ret = -E2BIG;
+               goto end;
+       }
+
+       memcpy(socket_addr.sun.sun_path, socket_path, path_length);
+
+       /* Support for abstract socket */
+       if (socket_addr.sun.sun_path[0] == '@')
+               socket_addr.sun.sun_path[0] = 0;
+
+       fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+       if (fd < 0) {
+               ret = -errno;
+               goto end;
+       }
+
+       if (connect(fd, &socket_addr.sa, offsetof(struct sockaddr_un, sun_path) + path_length) != 0) {
+               ret = -errno;
+               goto end;
+       }
+
+       written = write(fd, message, message_length);
+       if (written != (ssize_t) message_length) {
+               ret = written < 0 ? -errno : -EPROTO;
+               goto end;
+       }
+
+end:
+       if (fd > -1)
+               close(fd);
+       return ret; /* Notified! */
+}
+
+/* va_args variant of sd_notify */
+int sd_notifyf(int unset_environment, const char *format, ...)
+{
+       int r;
+       va_list args;
+       char *strp = NULL;
+
+       va_start(args, format);
+       strp = memvprintf(&strp, format, args);
+       va_end(args);
+
+       if (strp == NULL) {
+               r = -ENOMEM;
+               goto end;
+       }
+
+       r = sd_notify(unset_environment, strp);
+       free(strp);
+end:
+       return r;
+}
+