From: Luca Boccassi <[email protected]> coreutils is a core/essential package, that is pulled in every build chroot and so on. The functionality provided by libsystem is useful for full systems, but not so much for build systems or other such minimal environments.
Switch usage of the library to dlopen, so that it can be built in but runtime optional, and can be avoided if the specific functionality is not used, gracefully. If dlopen fails, fallback to the non-systemd method gracefully. If libsystemd headers are available at build time stamp the ELF binaries using the ELF dlopen metadata format as defined by: https://uapi-group.org/specifications/specs/elf_dlopen_metadata/ so that packaging tools for rpm/deb can automatically derive dependencies for it. --- lib/readutmp.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++- m4/readutmp.m4 | 20 +++++-- 2 files changed, 159 insertions(+), 7 deletions(-) diff --git a/lib/readutmp.c b/lib/readutmp.c index 6e43b5e956..f537321e9e 100644 --- a/lib/readutmp.c +++ b/lib/readutmp.c @@ -38,7 +38,16 @@ #endif #if READUTMP_USE_SYSTEMD # include <dirent.h> +# include <dlfcn.h> # include <systemd/sd-login.h> +# if HAVE_SYSTEMD_SD_DLOPEN_H +# include <systemd/sd-dlopen.h> + +SD_ELF_NOTE_DLOPEN ("systemd", + "Support for systemd sessions", + SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + "libsystemd.so.0"); +# endif #endif #if HAVE_SYS_SYSCTL_H && !(defined __GLIBC__ && defined __linux__) && !defined __minix @@ -67,6 +76,141 @@ /* Some helper functions. */ #include "boot-time-aux.h" +#if READUTMP_USE_SYSTEMD + +struct systemd_operations +{ + __typeof__ (&sd_get_sessions) sd_get_sessions; + __typeof__ (&sd_session_get_start_time) sd_session_get_start_time; + __typeof__ (&sd_session_get_seat) sd_session_get_seat; + __typeof__ (&sd_session_get_tty) sd_session_get_tty; + __typeof__ (&sd_session_get_type) sd_session_get_type; + __typeof__ (&sd_session_get_service) sd_session_get_service; + __typeof__ (&sd_session_get_uid) sd_session_get_uid; + __typeof__ (&sd_session_get_username) sd_session_get_username; + __typeof__ (&sd_session_get_leader) sd_session_get_leader; + __typeof__ (&sd_session_get_class) sd_session_get_class; + __typeof__ (&sd_session_get_remote_host) sd_session_get_remote_host; + __typeof__ (&sd_session_get_display) sd_session_get_display; + __typeof__ (&sd_session_get_remote_user) sd_session_get_remote_user; +}; + +static struct systemd_operations systemd_ops; + +/* Return a function pointer in HANDLE for SYMBOL. */ +static void * +systemd_symbol_address (void *handle, char const *symbol) +{ + void *address = dlsym (handle, symbol); + if (!address) + errno = ENOSYS; + return address; +} + +/* Load libsystemd and resolve all required symbols. Cache the result. + Return 0 on success. Return -1 with errno set to ENOSYS on failure. */ +static int +load_libsystemd (void) +{ + static int status = 0; + static void *handle = NULL; + int flags = RTLD_LAZY | RTLD_LOCAL; + + if (status) + { + if (status < 0) + errno = ENOSYS; + return status < 0 ? -1 : 0; + } + +# ifdef RTLD_NODELETE + flags |= RTLD_NODELETE; +# endif + handle = dlopen ("libsystemd.so.0", flags); + if (!handle) + goto fail; + + systemd_ops.sd_get_sessions = + systemd_symbol_address (handle, "sd_get_sessions"); + if (!systemd_ops.sd_get_sessions) + goto fail; + systemd_ops.sd_session_get_start_time = + systemd_symbol_address (handle, "sd_session_get_start_time"); + if (!systemd_ops.sd_session_get_start_time) + goto fail; + systemd_ops.sd_session_get_seat = + systemd_symbol_address (handle, "sd_session_get_seat"); + if (!systemd_ops.sd_session_get_seat) + goto fail; + systemd_ops.sd_session_get_tty = + systemd_symbol_address (handle, "sd_session_get_tty"); + if (!systemd_ops.sd_session_get_tty) + goto fail; + systemd_ops.sd_session_get_type = + systemd_symbol_address (handle, "sd_session_get_type"); + if (!systemd_ops.sd_session_get_type) + goto fail; + systemd_ops.sd_session_get_service = + systemd_symbol_address (handle, "sd_session_get_service"); + if (!systemd_ops.sd_session_get_service) + goto fail; + systemd_ops.sd_session_get_uid = + systemd_symbol_address (handle, "sd_session_get_uid"); + if (!systemd_ops.sd_session_get_uid) + goto fail; + systemd_ops.sd_session_get_username = + systemd_symbol_address (handle, "sd_session_get_username"); + if (!systemd_ops.sd_session_get_username) + goto fail; + systemd_ops.sd_session_get_leader = + systemd_symbol_address (handle, "sd_session_get_leader"); + if (!systemd_ops.sd_session_get_leader) + goto fail; + systemd_ops.sd_session_get_class = + systemd_symbol_address (handle, "sd_session_get_class"); + if (!systemd_ops.sd_session_get_class) + goto fail; + systemd_ops.sd_session_get_remote_host = + systemd_symbol_address (handle, "sd_session_get_remote_host"); + if (!systemd_ops.sd_session_get_remote_host) + goto fail; + systemd_ops.sd_session_get_display = + systemd_symbol_address (handle, "sd_session_get_display"); + if (!systemd_ops.sd_session_get_display) + goto fail; + systemd_ops.sd_session_get_remote_user = + systemd_symbol_address (handle, "sd_session_get_remote_user"); + if (!systemd_ops.sd_session_get_remote_user) + goto fail; + + status = 1; + return 0; + + fail: + if (handle) + dlclose (handle); + handle = NULL; + status = -1; + errno = ENOSYS; + return -1; +} + +# define sd_get_sessions systemd_ops.sd_get_sessions +# define sd_session_get_start_time systemd_ops.sd_session_get_start_time +# define sd_session_get_seat systemd_ops.sd_session_get_seat +# define sd_session_get_tty systemd_ops.sd_session_get_tty +# define sd_session_get_type systemd_ops.sd_session_get_type +# define sd_session_get_service systemd_ops.sd_session_get_service +# define sd_session_get_uid systemd_ops.sd_session_get_uid +# define sd_session_get_username systemd_ops.sd_session_get_username +# define sd_session_get_leader systemd_ops.sd_session_get_leader +# define sd_session_get_class systemd_ops.sd_session_get_class +# define sd_session_get_remote_host systemd_ops.sd_session_get_remote_host +# define sd_session_get_display systemd_ops.sd_session_get_display +# define sd_session_get_remote_user systemd_ops.sd_session_get_remote_user + +#endif + /* The following macros describe the 'struct UTMP_STRUCT_NAME', *not* 'struct gl_utmp'. */ #undef UT_USER @@ -977,7 +1121,7 @@ read_utmp (char const *file, idx_t *n_entries, STRUCT_UTMP **utmp_buf, int options) { # if READUTMP_USE_SYSTEMD - if (streq (file, UTMP_FILE)) + if (streq (file, UTMP_FILE) && load_libsystemd () == 0) /* Imitate reading UTMP_FILE, using systemd and Linux APIs. */ return read_utmp_from_systemd (n_entries, utmp_buf, options); # endif diff --git a/m4/readutmp.m4 b/m4/readutmp.m4 index 3eeec0d081..456f0258bd 100644 --- a/m4/readutmp.m4 +++ b/m4/readutmp.m4 @@ -1,5 +1,5 @@ # readutmp.m4 -# serial 32 +# serial 33 dnl Copyright (C) 2002-2026 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -10,10 +10,8 @@ AC_DEFUN([gl_READUTMP], [ AC_REQUIRE([gl_SYSTEMD_CHOICE]) - dnl Set READUTMP_LIB to '-lsystemd' or '', depending on whether use of - dnl systemd APIs is possible and desired (only the systemd login API, here). - dnl AC_LIB_LINKFLAGS_BODY would be overkill here, since few people install - dnl libsystemd in non-system directories. + dnl Set READUTMP_LIB to '-ldl' or '', depending on whether use of systemd + dnl APIs is possible and desired (only the systemd login API, here). READUTMP_LIB= if test "$SYSTEMD_CHOICE" = yes; then AC_CHECK_HEADER([systemd/sd-login.h]) @@ -35,10 +33,20 @@ AC_DEFUN([gl_READUTMP], [gl_cv_lib_readutmp_systemd=no]) LIBS="$gl_saved_LIBS" ]) + if test $gl_cv_lib_readutmp_systemd = yes; then + gl_saved_LIBS="$LIBS" + AC_SEARCH_LIBS([dlsym], [dl], + [case "$ac_cv_search_dlsym" in + 'none required') READUTMP_LIB= ;; + *) READUTMP_LIB=$ac_cv_search_dlsym ;; + esac], + [gl_cv_lib_readutmp_systemd=no]) + LIBS="$gl_saved_LIBS" + fi if test $gl_cv_lib_readutmp_systemd = yes; then AC_DEFINE([READUTMP_USE_SYSTEMD], [1], [Define if the readutmp module should use the systemd login API.]) - READUTMP_LIB='-lsystemd' + AC_CHECK_HEADERS([systemd/sd-dlopen.h]) fi fi fi -- 2.47.3
