diff options
author | Lennart Poettering <lennart@poettering.net> | 2024-01-30 14:50:35 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2024-04-04 18:16:45 +0200 |
commit | 1d98716ef7fef3abc078a2cee3156985b8562383 (patch) | |
tree | d1279d06b095778fade9923e370a4bc070a9a151 /src/shared | |
parent | watchdog: clarify that we set the *watchdog* timeout (diff) | |
download | systemd-1d98716ef7fef3abc078a2cee3156985b8562383.tar.xz systemd-1d98716ef7fef3abc078a2cee3156985b8562383.zip |
libkmod: turn into dlopen() dependency
As it turns out libkmod has quite a bunch of deps, including various
compressing libs and similar. By turning this into a dlopen()
dependency, we can make our depchain during install time quite a bit
smaller. In particular as inside of containers kmod doesn't help anyway
as CAP_SYS_MODULE is not available anyway.
While we are at it, also share the code that sets up logging/kmod
context.
After:
$ lddtree ./build/systemd
systemd => ./build/systemd (interpreter => /lib64/ld-linux-x86-64.so.2)
libsystemd-core-255.so => ./build/src/core/libsystemd-core-255.so
libaudit.so.1 => /lib64/libaudit.so.1
libcap-ng.so.0 => /lib64/libcap-ng.so.0
ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2
libm.so.6 => /lib64/libm.so.6
libmount.so.1 => /lib64/libmount.so.1
libblkid.so.1 => /lib64/libblkid.so.1
libseccomp.so.2 => /lib64/libseccomp.so.2
libselinux.so.1 => /lib64/libselinux.so.1
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0
libsystemd-shared-255.so => /home/lennart/projects/systemd/build/src/shared/libsystemd-shared-255.so
libacl.so.1 => /lib64/libacl.so.1
libattr.so.1 => /lib64/libattr.so.1
libcap.so.2 => /lib64/libcap.so.2
libcrypt.so.2 => /lib64/libcrypt.so.2
libgcrypt.so.20 => /lib64/libgcrypt.so.20
libgpg-error.so.0 => /lib64/libgpg-error.so.0
liblz4.so.1 => /lib64/liblz4.so.1
libcrypto.so.3 => /lib64/libcrypto.so.3
libz.so.1 => /lib64/libz.so.1
libpam.so.0 => /lib64/libpam.so.0
libeconf.so.0 => /lib64/libeconf.so.0
liblzma.so.5 => /lib64/liblzma.so.5
libzstd.so.1 => /lib64/libzstd.so.1
libc.so.6 => /lib64/libc.so.6
Before:
$ lddtree ./build/systemd
systemd => ./build/systemd (interpreter => /lib64/ld-linux-x86-64.so.2)
libsystemd-core-255.so => ./build/src/core/libsystemd-core-255.so
libaudit.so.1 => /lib64/libaudit.so.1
libcap-ng.so.0 => /lib64/libcap-ng.so.0
ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2
libkmod.so.2 => /lib64/libkmod.so.2
libzstd.so.1 => /lib64/libzstd.so.1
liblzma.so.5 => /lib64/liblzma.so.5
libz.so.1 => /lib64/libz.so.1
libcrypto.so.3 => /lib64/libcrypto.so.3
libgcc_s.so.1 => /lib64/libgcc_s.so.1
libm.so.6 => /lib64/libm.so.6
libmount.so.1 => /lib64/libmount.so.1
libblkid.so.1 => /lib64/libblkid.so.1
libseccomp.so.2 => /lib64/libseccomp.so.2
libselinux.so.1 => /lib64/libselinux.so.1
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0
libsystemd-shared-255.so => /home/lennart/projects/systemd/build/src/shared/libsystemd-shared-255.so
libacl.so.1 => /lib64/libacl.so.1
libattr.so.1 => /lib64/libattr.so.1
libcap.so.2 => /lib64/libcap.so.2
libcrypt.so.2 => /lib64/libcrypt.so.2
libgcrypt.so.20 => /lib64/libgcrypt.so.20
libgpg-error.so.0 => /lib64/libgpg-error.so.0
liblz4.so.1 => /lib64/liblz4.so.1
libpam.so.0 => /lib64/libpam.so.0
libeconf.so.0 => /lib64/libeconf.so.0
libc.so.6 => /lib64/libc.so.6
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/meson.build | 7 | ||||
-rw-r--r-- | src/shared/module-util.c | 114 | ||||
-rw-r--r-- | src/shared/module-util.h | 50 |
3 files changed, 146 insertions, 25 deletions
diff --git a/src/shared/meson.build b/src/shared/meson.build index 4c9b45434e..71db6d8694 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -118,6 +118,7 @@ shared_sources = files( 'macvlan-util.c', 'mkdir-label.c', 'mkfs-util.c', + 'module-util.c', 'mount-setup.c', 'mount-util.c', 'net-condition.c', @@ -236,10 +237,6 @@ if conf.get('HAVE_LIBBPF') == 1 shared_sources += files('bpf-link.c') endif -if conf.get('HAVE_KMOD') == 1 - shared_sources += files('module-util.c') -endif - if conf.get('HAVE_PAM') == 1 shared_sources += files('pam-util.c') endif @@ -324,7 +321,7 @@ libshared_deps = [threads, libdl, libgcrypt, libiptc_cflags, - libkmod, + libkmod_cflags, liblz4_cflags, libmount, libopenssl, diff --git a/src/shared/module-util.c b/src/shared/module-util.c index 907990d96e..612ab9c9c5 100644 --- a/src/shared/module-util.c +++ b/src/shared/module-util.c @@ -6,6 +6,44 @@ #include "proc-cmdline.h" #include "strv.h" +#if HAVE_KMOD + +static void *libkmod_dl = NULL; + +DLSYM_FUNCTION(kmod_list_next); +DLSYM_FUNCTION(kmod_load_resources); +DLSYM_FUNCTION(kmod_module_get_initstate); +DLSYM_FUNCTION(kmod_module_get_module); +DLSYM_FUNCTION(kmod_module_get_name); +DLSYM_FUNCTION(kmod_module_new_from_lookup); +DLSYM_FUNCTION(kmod_module_probe_insert_module); +DLSYM_FUNCTION(kmod_module_unref); +DLSYM_FUNCTION(kmod_module_unref_list); +DLSYM_FUNCTION(kmod_new); +DLSYM_FUNCTION(kmod_set_log_fn); +DLSYM_FUNCTION(kmod_unref); +DLSYM_FUNCTION(kmod_validate_resources); + +int dlopen_libkmod(void) { + return dlopen_many_sym_or_warn( + &libkmod_dl, + "libkmod.so.2", + LOG_DEBUG, + DLSYM_ARG(kmod_list_next), + DLSYM_ARG(kmod_load_resources), + DLSYM_ARG(kmod_module_get_initstate), + DLSYM_ARG(kmod_module_get_module), + DLSYM_ARG(kmod_module_get_name), + DLSYM_ARG(kmod_module_new_from_lookup), + DLSYM_ARG(kmod_module_probe_insert_module), + DLSYM_ARG(kmod_module_unref), + DLSYM_ARG(kmod_module_unref_list), + DLSYM_ARG(kmod_new), + DLSYM_ARG(kmod_set_log_fn), + DLSYM_ARG(kmod_unref), + DLSYM_ARG(kmod_validate_resources)); +} + static int denylist_modules(const char *p, char ***denylist) { _cleanup_strv_free_ char **k = NULL; int r; @@ -41,19 +79,21 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat } int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose) { - const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST; - struct kmod_list *itr; - _cleanup_(kmod_module_unref_listp) struct kmod_list *modlist = NULL; + _cleanup_(sym_kmod_module_unref_listp) struct kmod_list *modlist = NULL; _cleanup_strv_free_ char **denylist = NULL; bool denylist_parsed = false; + struct kmod_list *itr; int r; + assert(ctx); + assert(module); + /* verbose==true means we should log at non-debug level if we * fail to find or load the module. */ log_debug("Loading module: %s", module); - r = kmod_module_new_from_lookup(ctx, module, &modlist); + r = sym_kmod_module_new_from_lookup(ctx, module, &modlist); if (r < 0) return log_full_errno(verbose ? LOG_ERR : LOG_DEBUG, r, "Failed to look up module alias '%s': %m", module); @@ -63,32 +103,37 @@ int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose) SYNTHETIC_ERRNO(ENOENT), "Failed to find module '%s'", module); - kmod_list_foreach(itr, modlist) { - _cleanup_(kmod_module_unrefp) struct kmod_module *mod = NULL; + sym_kmod_list_foreach(itr, modlist) { + _cleanup_(sym_kmod_module_unrefp) struct kmod_module *mod = NULL; int state, err; - mod = kmod_module_get_module(itr); - state = kmod_module_get_initstate(mod); + mod = sym_kmod_module_get_module(itr); + state = sym_kmod_module_get_initstate(mod); switch (state) { case KMOD_MODULE_BUILTIN: log_full(verbose ? LOG_INFO : LOG_DEBUG, - "Module '%s' is built in", kmod_module_get_name(mod)); + "Module '%s' is built in", sym_kmod_module_get_name(mod)); break; case KMOD_MODULE_LIVE: - log_debug("Module '%s' is already loaded", kmod_module_get_name(mod)); + log_debug("Module '%s' is already loaded", sym_kmod_module_get_name(mod)); break; default: - err = kmod_module_probe_insert_module(mod, probe_flags, - NULL, NULL, NULL, NULL); + err = sym_kmod_module_probe_insert_module( + mod, + KMOD_PROBE_APPLY_BLACKLIST, + /* extra_options= */ NULL, + /* run_install= */ NULL, + /* data= */ NULL, + /* print_action= */ NULL); if (err == 0) log_full(verbose ? LOG_INFO : LOG_DEBUG, - "Inserted module '%s'", kmod_module_get_name(mod)); + "Inserted module '%s'", sym_kmod_module_get_name(mod)); else if (err == KMOD_PROBE_APPLY_BLACKLIST) log_full(verbose ? LOG_INFO : LOG_DEBUG, - "Module '%s' is deny-listed (by kmod)", kmod_module_get_name(mod)); + "Module '%s' is deny-listed (by kmod)", sym_kmod_module_get_name(mod)); else { assert(err < 0); @@ -102,9 +147,9 @@ int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose) denylist_parsed = true; } - if (strv_contains(denylist, kmod_module_get_name(mod))) { + if (strv_contains(denylist, sym_kmod_module_get_name(mod))) { log_full(verbose ? LOG_INFO : LOG_DEBUG, - "Module '%s' is deny-listed (by kernel)", kmod_module_get_name(mod)); + "Module '%s' is deny-listed (by kernel)", sym_kmod_module_get_name(mod)); continue; } } @@ -115,7 +160,7 @@ int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose) LOG_ERR, err, "Failed to insert module '%s': %m", - kmod_module_get_name(mod)); + sym_kmod_module_get_name(mod)); if (!IN_SET(err, -ENODEV, -ENOENT)) r = err; } @@ -124,3 +169,38 @@ int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose) return r; } + +_printf_(6,0) static void systemd_kmod_log( + void *data, + int priority, + const char *file, + int line, + const char *fn, + const char *format, + va_list args) { + + log_internalv(priority, 0, file, line, fn, format, args); +} + +int module_setup_context(struct kmod_ctx **ret) { + _cleanup_(sym_kmod_unrefp) struct kmod_ctx *ctx = NULL; + int r; + + assert(ret); + + r = dlopen_libkmod(); + if (r < 0) + return r; + + ctx = sym_kmod_new(NULL, NULL); + if (!ctx) + return -ENOMEM; + + (void) sym_kmod_load_resources(ctx); + sym_kmod_set_log_fn(ctx, systemd_kmod_log, NULL); + + *ret = TAKE_PTR(ctx); + return 0; +} + +#endif diff --git a/src/shared/module-util.h b/src/shared/module-util.h index 8ca6a06a07..081973802b 100644 --- a/src/shared/module-util.h +++ b/src/shared/module-util.h @@ -1,12 +1,56 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "dlfcn-util.h" + +#if HAVE_KMOD + #include <libkmod.h> #include "macro.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_ctx*, kmod_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_module*, kmod_module_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct kmod_list*, kmod_module_unref_list, NULL); +DLSYM_PROTOTYPE(kmod_list_next); +DLSYM_PROTOTYPE(kmod_load_resources); +DLSYM_PROTOTYPE(kmod_module_get_initstate); +DLSYM_PROTOTYPE(kmod_module_get_module); +DLSYM_PROTOTYPE(kmod_module_get_name); +DLSYM_PROTOTYPE(kmod_module_new_from_lookup); +DLSYM_PROTOTYPE(kmod_module_probe_insert_module); +DLSYM_PROTOTYPE(kmod_module_unref); +DLSYM_PROTOTYPE(kmod_module_unref_list); +DLSYM_PROTOTYPE(kmod_new); +DLSYM_PROTOTYPE(kmod_set_log_fn); +DLSYM_PROTOTYPE(kmod_unref); +DLSYM_PROTOTYPE(kmod_validate_resources); + +int dlopen_libkmod(void); + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_ctx*, sym_kmod_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_module*, sym_kmod_module_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct kmod_list*, sym_kmod_module_unref_list, NULL); + +#define sym_kmod_list_foreach(list_entry, first_entry) \ + for (list_entry = first_entry; \ + list_entry != NULL; \ + list_entry = sym_kmod_list_next(first_entry, list_entry)) int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose); +int module_setup_context(struct kmod_ctx **ret); + +#else + +struct kmod_ctx; + +static inline int dlopen_libkmod(void) { + return -EOPNOTSUPP; +} + +static inline int module_setup_context(struct kmod_ctx **ret) { + return -EOPNOTSUPP; +} + +static inline int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose) { + return -EOPNOTSUPP; +} + +#endif |