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. Use sd-dlopen to 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 | 149 +++++++++++++++++++++++++++++++++++++++++ m4/readutmp.m4 | 32 +++++---- modules/readutmp | 4 +- modules/readutmp-tests | 2 +- 4 files changed, 172 insertions(+), 15 deletions(-) diff --git a/lib/readutmp.c b/lib/readutmp.c index 6e43b5e956..85833663af 100644 --- a/lib/readutmp.c +++ b/lib/readutmp.c @@ -38,7 +38,15 @@ #endif #if READUTMP_USE_SYSTEMD # include <dirent.h> +# include <dlfcn.h> # include <systemd/sd-login.h> +# include "glthread/once.h" +# include "sd-dlopen.h" + +SD_ELF_NOTE_DLOPEN ("systemd", + "Support for systemd sessions", + SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + LIBSYSTEMD_SONAME); #endif #if HAVE_SYS_SYSCTL_H && !(defined __GLIBC__ && defined __linux__) && !defined __minix @@ -67,6 +75,144 @@ /* 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; +static int load_status; +gl_once_define (static, load_once) + +/* 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. */ +static void +do_load_libsystemd (void) +{ + void *handle; + int flags = RTLD_LAZY | RTLD_LOCAL; + +# ifdef RTLD_NODELETE + flags |= RTLD_NODELETE; +# endif + handle = dlopen (LIBSYSTEMD_SONAME, 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; + + return; + + fail: + if (handle) + dlclose (handle); + load_status = -1; +} + +/* Initialize the libsystemd operations once. Return 0 on success. Return -1 + with errno set to ENOSYS on failure. */ +static int +load_libsystemd (void) +{ + gl_once (load_once, do_load_libsystemd); + if (load_status < 0) + { + errno = ENOSYS; + return -1; + } + return 0; +} + +# 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 @@ -797,6 +943,9 @@ guess_pty_name (uid_t uid, const struct timespec at) static int read_utmp_from_systemd (idx_t *n_entries, STRUCT_UTMP **utmp_buf, int options) { + if (load_libsystemd () < 0) + return -1; + /* Fill entries, simulating what a utmp file would contain. */ struct utmp_alloc a = { NULL, 0, 0, 0 }; diff --git a/m4/readutmp.m4 b/m4/readutmp.m4 index 3eeec0d081..5622b892c3 100644 --- a/m4/readutmp.m4 +++ b/m4/readutmp.m4 @@ -1,5 +1,5 @@ # readutmp.m4 -# serial 32 +# serial 36 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, @@ -9,18 +9,18 @@ dnl This file is offered as-is, without any warranty. AC_DEFUN([gl_READUTMP], [ AC_REQUIRE([gl_SYSTEMD_CHOICE]) + AC_REQUIRE([gl_LIBDL]) - 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 LIBDL 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]) if test $ac_cv_header_systemd_sd_login_h = yes; then - AC_CACHE_CHECK([for libsystemd version >= 254], - [gl_cv_lib_readutmp_systemd], - [gl_saved_LIBS="$LIBS" + AC_CACHE_CHECK([for libsystemd version >= 254 shared library name], + [gl_cv_lib_readutmp_systemd_soname], + [gl_cv_lib_readutmp_systemd_soname=no + gl_saved_LIBS="$LIBS" LIBS="$LIBS -lsystemd" AC_LINK_IFELSE( [AC_LANG_PROGRAM([[ @@ -31,15 +31,21 @@ AC_DEFUN([gl_READUTMP], sd_session_get_start_time ("1", &st); ]]) ], - [gl_cv_lib_readutmp_systemd=yes], - [gl_cv_lib_readutmp_systemd=no]) + [gl_DLOPEN_SONAME([gl_systemd_soname], + [libsystemd\.so\.[[.0-9]]*]) + AS_CASE([$gl_systemd_soname], + [libsystemd.so.*], + [gl_cv_lib_readutmp_systemd_soname=$gl_systemd_soname])]) LIBS="$gl_saved_LIBS" ]) - if test $gl_cv_lib_readutmp_systemd = yes; then + AS_CASE([$gl_cv_lib_readutmp_systemd_soname], + [libsystemd.so.*], + [AC_DEFINE_UNQUOTED([LIBSYSTEMD_SONAME], + ["$gl_cv_lib_readutmp_systemd_soname"], + [libsystemd shared object name]) AC_DEFINE([READUTMP_USE_SYSTEMD], [1], [Define if the readutmp module should use the systemd login API.]) - READUTMP_LIB='-lsystemd' - fi + READUTMP_LIB=$LIBDL]) fi fi AC_SUBST([READUTMP_LIB]) diff --git a/modules/readutmp b/modules/readutmp index f74c533f78..9ccfcf97bc 100644 --- a/modules/readutmp +++ b/modules/readutmp @@ -17,6 +17,8 @@ bool stdcountof-h stdint-h memeq +once +sd-dlopen streq strnlen time-h @@ -34,7 +36,7 @@ Include: Link: $(READUTMP_LIB) -$(LTLIBINTL) when linking with libtool, $(LIBINTL) otherwise +$(LIBTHREAD) License: GPL diff --git a/modules/readutmp-tests b/modules/readutmp-tests index c21fe9c4be..322c15a5c0 100644 --- a/modules/readutmp-tests +++ b/modules/readutmp-tests @@ -12,4 +12,4 @@ configure.ac: Makefile.am: TESTS += test-readutmp check_PROGRAMS += test-readutmp -test_readutmp_LDADD = $(LDADD) @READUTMP_LIB@ $(LIBINTL) +test_readutmp_LDADD = $(LDADD) @READUTMP_LIB@ -- 2.47.3
