From d48585199b83bee0b3d1077ff250a63ffae7ce51 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Sun, 19 Oct 2025 12:47:07 +0200 Subject: [PATCH] MINOR: systemd: reimplement sd_listen_fds and sd_listen_fds_with_names Reimplement both functions from systemd. https://www.freedesktop.org/software/systemd/man/latest/sd_listen_fds.html These two functions are used to get the numbers of FDs that systemd is passing to the service as part of the socket-based activation logic, and the name associated to each FD. --- include/haproxy/systemd.h | 3 + src/systemd.c | 117 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/include/haproxy/systemd.h b/include/haproxy/systemd.h index 65b0ab616..2ad688413 100644 --- a/include/haproxy/systemd.h +++ b/include/haproxy/systemd.h @@ -4,4 +4,7 @@ int sd_notify(int unset_environment, const char *message); int sd_notifyf(int unset_environment, const char *format, ...); +int sd_listen_fds_with_names(int unset_environment, char ***names); +int sd_listen_fds(int unset_environment); + #endif diff --git a/src/systemd.c b/src/systemd.c index b58117ae4..262bbe6f9 100644 --- a/src/systemd.c +++ b/src/systemd.c @@ -138,3 +138,120 @@ end: return r; } +/* + * standalone reimplementation of sd_listen_fd() from the libsystemd + * Return value: + * -errno in case of error + * =0 $LISTEN_FDS was not set + * >0 the number of file descriptors passed + * + * When unset_environement is set, unsetenv LISTEN_FDS, LISTEN_PID, LISTEN_FDNAMES. + */ +int sd_listen_fds(int unset_environment) +{ + long int nfds; + const char *env; + int ret = 0; + char *end; + + env = getenv("LISTEN_FDS"); + if (!env) + goto end; + + nfds = strtol(env, &end, 10); + if (*end) { + ret = -EINVAL; + goto end; + } + if (nfds > INT_MAX) { + ret = -ERANGE; + goto end; + } + + ret = nfds; + +end: + if (unset_environment) { + unsetenv("LISTEN_FDS"); + unsetenv("LISTEN_PID"); + unsetenv("LISTEN_FDNAMES"); + } + return ret; +} + +/* + * standalone reimplementation of sd_listen_fd_with_names from the libsystemd + * might differ from official libsystemd one + * Return value: + * -errno in case of error + * =0 $LISTEN_FDS was not set + * >0 the number of file descriptor passed + * + * When unset_environement is set, unsetenv LISTEN_FDS, LISTEN_PID, LISTEN_FDNAMES. + * If names is non NULL, allocate a char ** array which is NULL-terminated and needs to be freed. + * Allocate sd_listen_fds()+1 elements in the array. + */ +int sd_listen_fds_with_names(int unset_environment, char ***names) +{ + const char *env; + long int nfds; + int ret = 0; + char **n = NULL, **p; + int i = 0; + const char *s = NULL, *e; + + nfds = sd_listen_fds(0); + env = getenv("LISTEN_FDNAMES"); + if (!env || nfds <= 0) { + ret = nfds; + goto end; + } + + n = calloc(nfds + 1, sizeof(*n)); + if (!n) { + ret = -ENOMEM; + goto end; + } + + while (1) { + if (s == NULL) + s = env; + + if (*env == ':' || *env == '\0') { + e = env; + n[i] = calloc(e - s + 1, sizeof(**names)); + if (!n[i]) { + ret = -ENOMEM; + goto end; + } + memcpy(n[i], s, e - s); + i++; + /* must never be more than nfds */ + if (i >= nfds || e == NULL) + break; + s = e = NULL; + } + env++; + } + + /* n is free upon error so set it to NULL */ + *names = n; + n = NULL; + +end: + /* free the array */ + p = n; + while (n && *n) { + free(*n); + n++; + } + free(p); + + if (unset_environment) { + unsetenv("LISTEN_FDS"); + unsetenv("LISTEN_PID"); + unsetenv("LISTEN_FDNAMES"); + } + return ret; +} +