From ad914843c6072d64a8e265bb3fda1c1d61f46df6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Dec 2020 14:09:37 +0100 Subject: [PATCH 1/4] qrcode-util: make dlopen() logic more like the other cases Let's add a dlopen_qrencode() function that does the actual dlopen() stuff and caches the result. This is useful so that we later can automatically test for all dlopen hookups to work correctly. --- src/shared/qrcode-util.c | 48 ++++++++++++++++++++++++++++------------ src/shared/qrcode-util.h | 2 ++ 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/shared/qrcode-util.c b/src/shared/qrcode-util.c index f7d2d984c9..6b9ff8531b 100644 --- a/src/shared/qrcode-util.c +++ b/src/shared/qrcode-util.c @@ -5,12 +5,45 @@ #if HAVE_QRENCODE #include +#include "alloc-util.h" #include "dlfcn-util.h" #include "locale-util.h" #include "terminal-util.h" #define ANSI_WHITE_ON_BLACK "\033[40;37;1m" +static void *qrcode_dl = NULL; + +static QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) = NULL; +static void (*sym_QRcode_free)(QRcode *qrcode) = NULL; + +int dlopen_qrencode(void) { + _cleanup_(dlclosep) void *dl = NULL; + int r; + + if (qrcode_dl) + return 0; /* Already loaded */ + + dl = dlopen("libqrencode.so.4", RTLD_LAZY); + if (!dl) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "libqrcode support is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_DEBUG, + DLSYM_ARG(QRcode_encodeString), + DLSYM_ARG(QRcode_free), + NULL); + if (r < 0) + return r; + + /* Note that we never release the reference here, because there's no real reason to, after all this + * was traditionally a regular shared library dependency which lives forever too. */ + qrcode_dl = TAKE_PTR(dl); + return 1; +} + static void print_border(FILE *output, unsigned width) { /* Four rows of border */ for (unsigned y = 0; y < 4; y += 2) { @@ -65,9 +98,6 @@ static void write_qrcode(FILE *output, QRcode *qr) { } int print_qrcode(FILE *out, const char *header, const char *string) { - QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); - void (*sym_QRcode_free)(QRcode *qrcode); - _cleanup_(dlclosep) void *dl = NULL; QRcode* qr; int r; @@ -76,17 +106,7 @@ int print_qrcode(FILE *out, const char *header, const char *string) { if (!is_locale_utf8() || !colors_enabled()) return -EOPNOTSUPP; - dl = dlopen("libqrencode.so.4", RTLD_LAZY); - if (!dl) - return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "QRCODE support is not installed: %s", dlerror()); - - r = dlsym_many_and_warn( - dl, - LOG_DEBUG, - DLSYM_ARG(QRcode_encodeString), - DLSYM_ARG(QRcode_free), - NULL); + r = dlopen_qrencode(); if (r < 0) return r; diff --git a/src/shared/qrcode-util.h b/src/shared/qrcode-util.h index 6fc45c93d1..b64ecce80a 100644 --- a/src/shared/qrcode-util.h +++ b/src/shared/qrcode-util.h @@ -5,6 +5,8 @@ #include #if HAVE_QRENCODE +int dlopen_qrencode(void); + int print_qrcode(FILE *out, const char *header, const char *string); #else static inline int print_qrcode(FILE *out, const char *header, const char *string) { From 68fdc72cfe19777b8f39a6a13b659e79ead4bee9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 7 Dec 2020 14:15:36 +0100 Subject: [PATCH 2/4] test: add test that dlopen()'s all our weak library deps once This test should ensure we notice if distros update shared libraries that broke so name, and we still use the old soname. (In contrast to what the commit summary says, this currently doesn#t cover really all such deps, specifically xkbcommon and PCRE are missing, since they currently aren't loaded from src/shared/. This is stuff to fix later) --- src/test/meson.build | 4 ++++ src/test/test-dlopen-so.c | 40 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/test/test-dlopen-so.c diff --git a/src/test/meson.build b/src/test/meson.build index 9e781f88dc..3afe5d58cb 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -71,6 +71,10 @@ tests += [ libshared], []], + [['src/test/test-dlopen-so.c'], + [libshared], + []], + [['src/test/test-job-type.c'], [libcore, libshared], diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c new file mode 100644 index 0000000000..6436dc600f --- /dev/null +++ b/src/test/test-dlopen-so.c @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "cryptsetup-util.h" +#include "idn-util.h" +#include "macro.h" +#include "main-func.h" +#include "pwquality-util.h" +#include "qrcode-util.h" +#include "tests.h" + +static int run(int argc, char **argv) { + test_setup_logging(LOG_DEBUG); + + /* Try to load each of our weak library dependencies once. This is supposed to help finding cases + * where .so versions change and distributions update, but systemd doesn't have the new so names + * around yet. */ + +#if HAVE_LIBIDN2 || HAVE_LIBIDN + assert_se(dlopen_idn() >= 0); +#endif + +#if HAVE_LIBCRYPTSETUP + assert_se(dlopen_cryptsetup() >= 0); +#endif + +#if HAVE_PWQUALITY + assert_se(dlopen_pwquality() >= 0); +#endif + +#if HAVE_QRENCODE + assert_se(dlopen_qrencode() >= 0); +#endif + + return 0; +} + +DEFINE_MAIN_FUNCTION(run); From b7fca1b059f9345c0539e07febfa851f80a81f6b Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 9 Dec 2020 10:15:36 +0100 Subject: [PATCH 3/4] test: pull in weak deps into tests (Pulled from @bluca's comment here: https://github.com/systemd/systemd/pull/17884#issuecomment-740005624 and turned into a commit by @poettering) --- test/test-functions | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test-functions b/test/test-functions index d5da8e0ea5..91cd7312d6 100644 --- a/test/test-functions +++ b/test/test-functions @@ -676,6 +676,19 @@ install_missing_libraries() { for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/{,tests/{,manual/,unsafe/}}*; do LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i):$(get_ldpath $i)/src/udev" inst_libs $i done + + # A number of dependencies is now optional via dlopen, so the install + # script will not pick them up, since it looks at linkage. + for lib in libcryptsetup libidn libidn2 pwquality libqrencode; do + if pkg-config --exists ${lib}; then + path=$(pkg-config --variable=libdir ${lib}) + if ! [[ ${lib} =~ ^lib ]]; then + lib="lib${lib}" + fi + inst_libs "${path}/${lib}.so" + inst_library "${path}/${lib}.so" + fi + done } cleanup_loopdev() { From a6c7811f0d3888e2fa545cd80d7815049b5cb084 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Wed, 9 Dec 2020 13:33:54 +0100 Subject: [PATCH 4/4] meson: specify correct libqrencode version in meson dep --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 5d9413a5bb..513b841ac5 100644 --- a/meson.build +++ b/meson.build @@ -1117,6 +1117,7 @@ conf.set10('HAVE_LIBIPTC', have) want_qrencode = get_option('qrencode') if want_qrencode != 'false' and not skip_deps libqrencode = dependency('libqrencode', + version : '>= 4', required : want_qrencode == 'true') have = libqrencode.found() else