]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
libc,shared: detect newer library symbols at runtime 42065/head
authorDaan De Meyer <daan@amutable.com>
Tue, 12 May 2026 14:29:18 +0000 (16:29 +0200)
committerDaan De Meyer <daan@amutable.com>
Wed, 13 May 2026 08:29:50 +0000 (10:29 +0200)
For libc syscall wrappers (pidfd_open, fsopen, openat2, etc.) we previously
gated the calls behind build-time HAVE_* checks. Replace these with shim
functions in src/libc/ that fall back to the raw syscall at runtime when the
loaded glibc lacks the symbol. The infrastructure lives in src/libc/libc-shim.h:
DEFINE_SYSCALL_SHIM falls back to a direct syscall, DEFINE_LIBC_SHIM returns
ENOSYS (for posix_spawn-family helpers that have no corresponding syscall), and
DEFINE_LIBC_ERRNO_SHIM sets errno=ENOSYS and returns -1 (for read/write-style
helpers). The weak reference to the libc symbol is bound via __asm__(\"name\")
rename so the bare libc identifier never appears as a C token — this avoids
both #undef boilerplate against override-header redirects and the resulting
-Wredundant-decls warning. Drop the corresponding cc.has_function() loop from
meson.build.

For optional libraries (libcryptsetup, libdw, libarchive), drop the per-symbol
HAVE_* checks. Always declare the prototypes, suppressing the redundant-decl
warnings via DISABLE_WARNING_REDUNDANT_DECLS and NOLINT, and resolve the symbols
after the main dlopen via a new DLSYM_OPTIONAL() helper that only assigns on
success. libcryptsetup's crypt_set_keyring_to_link / crypt_token_set_external_path
and libarchive's *_is_set wrappers use fallback functions as their pointer
initializers (returning -ENOSYS and 0 respectively), so call sites can invoke
the symbol unconditionally and just check for -ENOSYS where the \"not supported\"
distinction matters.

The same shim treatment applies to pidfd_spawn / posix_spawnattr_setcgroup_np
(src/libc/spawn.c) and epoll_pwait2 (src/libc/epoll.c), with corresponding
override headers in src/include/override/spawn.h and
src/include/override/sys/epoll.h. posix_spawn_wrapper() in process-util.c and
epoll_wait_usec() in sd-event.c now detect ENOSYS in the return value instead
of checking the function pointer, falling back to plain posix_spawn() and
epoll_wait() respectively. coredump-config and coredump-submit get a
dlopen_dw_has_dwfl_set_sysroot() helper. The kexec arch gate now uses
defined(__NR_kexec_file_load) directly; pidfd.h uses __has_include_next() to
decide whether to pull in glibc's header.

This lets binaries built against newer glibc / libcryptsetup / libdw /
libarchive headers still load and run on older targets where these symbols are
absent.

51 files changed:
meson.build
src/basic/dlfcn-util.h
src/basic/process-util.c
src/coredump/coredump-config.c
src/coredump/coredump-submit.c
src/cryptsetup/cryptsetup.c
src/include/musl/stdio.h
src/include/override/fcntl.h
src/include/override/sched.h
src/include/override/signal.h
src/include/override/spawn.h [new file with mode: 0644]
src/include/override/sys/bpf.h
src/include/override/sys/epoll.h [new file with mode: 0644]
src/include/override/sys/ioprio.h
src/include/override/sys/kcmp.h
src/include/override/sys/kexec.h
src/include/override/sys/keyctl.h
src/include/override/sys/mempolicy.h
src/include/override/sys/mount.h
src/include/override/sys/pidfd.h
src/include/override/sys/quota.h
src/include/override/sys/stat.h
src/include/override/sys/xattr.h
src/include/override/unistd.h
src/libc/bpf.c
src/libc/epoll.c [new file with mode: 0644]
src/libc/fcntl.c
src/libc/ioprio.c
src/libc/kcmp.c
src/libc/kexec.c
src/libc/keyctl.c
src/libc/libc-shim.h [new file with mode: 0644]
src/libc/mempolicy.c
src/libc/meson.build
src/libc/mount.c
src/libc/musl/stdio.c
src/libc/pidfd.c
src/libc/quota.c
src/libc/sched.c
src/libc/signal.c
src/libc/spawn.c [new file with mode: 0644]
src/libc/stat.c
src/libc/unistd.c
src/libc/xattr.c
src/libsystemd/sd-event/sd-event.c
src/shared/cryptsetup-util.c
src/shared/cryptsetup-util.h
src/shared/elf-util.c
src/shared/elf-util.h
src/shared/libarchive-util.c
src/shared/libarchive-util.h

index 2e78b359e6ea63ebdff82812779e73cd7743736b..e84303c9cbab66b92135491d563f7e59d782b7a2 100644 (file)
@@ -582,43 +582,6 @@ long_max = cc.compute_int(
 assert(long_max > 100000)
 conf.set_quoted('LONG_MAX_STR', f'@long_max@')
 
-foreach ident : [
-        ['renameat2',         '''#include <stdio.h>'''],        # since musl-1.2.6
-        ['set_mempolicy',     '''#include <sys/syscall.h>'''],  # declared at numaif.h provided by libnuma, which we do not use
-        ['get_mempolicy',     '''#include <sys/syscall.h>'''],  # declared at numaif.h provided by libnuma, which we do not use
-        ['epoll_pwait2',      '''#include <sys/epoll.h>'''],    # since glibc-2.35
-        ['fsconfig',          '''#include <sys/mount.h>'''],    # since glibc-2.36
-        ['fsmount',           '''#include <sys/mount.h>'''],    # since glibc-2.36
-        ['fsopen',            '''#include <sys/mount.h>'''],    # since glibc-2.36
-        ['mount_setattr',     '''#include <sys/mount.h>'''],    # since glibc-2.36
-        ['move_mount',        '''#include <sys/mount.h>'''],    # since glibc-2.36
-        ['open_tree',         '''#include <sys/mount.h>'''],    # since glibc-2.36
-        ['openat2',           '''#include <fcntl.h>'''],        # since glibc-2.42
-        ['pidfd_open',        '''#include <sys/pidfd.h>'''],    # since glibc-2.36
-        ['pidfd_send_signal', '''#include <sys/pidfd.h>'''],    # since glibc-2.36
-        ['pidfd_spawn',       '''#include <spawn.h>'''],        # since glibc-2.39
-        ['sched_setattr',     '''#include <sched.h>'''],        # since glibc-2.41
-        ['ioprio_get',        '''#include <sched.h>'''],        # no known header declares ioprio_get
-        ['ioprio_set',        '''#include <sched.h>'''],        # no known header declares ioprio_set
-        ['rt_tgsigqueueinfo', '''#include <signal.h>'''],       # no known header declares rt_tgsigqueueinfo
-        ['open_tree_attr',    '''#include <sys/mount.h>'''],    # no known header declares open_tree_attr
-        ['quotactl_fd',       '''#include <sys/quota.h>'''],    # no known header declares quotactl_fd
-        ['fchmodat2',         '''#include <sys/stat.h>'''],     # no known header declares fchmodat2
-        ['bpf',               '''#include <sys/syscall.h>'''],  # no known header declares bpf
-        ['kcmp',              '''#include <sys/syscall.h>'''],  # no known header declares kcmp
-        ['kexec_file_load',   '''#include <sys/syscall.h>'''],  # no known header declares kexec_file_load
-        ['keyctl',            '''#include <sys/syscall.h>'''],  # no known header declares keyctl
-        ['add_key',           '''#include <sys/syscall.h>'''],  # no known header declares add_key
-        ['request_key',       '''#include <sys/syscall.h>'''],  # no known header declares request_key
-        ['setxattrat',        '''#include <sys/xattr.h>'''],    # no known header declares setxattrat
-        ['removexattrat',     '''#include <sys/xattr.h>'''],    # no known header declares removexattrat
-        ['pivot_root',        '''#include <unistd.h>'''],       # no known header declares pivot_root
-]
-
-        have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
-        conf.set10('HAVE_' + ident[0].to_upper(), have)
-endforeach
-
 #####################################################################
 
 awk    = find_program('awk')
@@ -1203,18 +1166,6 @@ conf.set10('HAVE_LIBCRYPTSETUP', have)
 conf.set10('HAVE_LIBCRYPTSETUP_PLUGINS',
            libcryptsetup_plugins.allowed() and have)
 
-foreach ident : [
-                'crypt_set_keyring_to_link',     # 2.7
-                'crypt_token_set_external_path', # 2.7
-        ]
-
-        have_ident = have and cc.has_function(
-                ident,
-                prefix : '#include <libcryptsetup.h>',
-                dependencies : libcryptsetup)
-        conf.set10('HAVE_' + ident.to_upper(), have_ident)
-endforeach
-
 libcurl = dependency('libcurl',
                      version : '>= 7.32.0',
                      required : get_option('libcurl'))
@@ -1292,10 +1243,6 @@ libelf = dependency('libelf',
 libelf_cflags = libelf.partial_dependency(includes: true, compile_args: true)
 conf.set10('HAVE_ELFUTILS', libdw.found() and libelf.found())
 
-# New in elfutils 0.192
-conf.set10('HAVE_DWFL_SET_SYSROOT',
-           libdw.found() and cc.has_function('dwfl_set_sysroot', dependencies : libdw))
-
 libz = dependency('zlib',
                   required : get_option('zlib'))
 conf.set10('HAVE_ZLIB', libz.found())
@@ -1365,16 +1312,6 @@ libarchive = dependency('libarchive',
 libarchive_cflags = libarchive.partial_dependency(includes: true, compile_args: true)
 conf.set10('HAVE_LIBARCHIVE', libarchive.found())
 
-foreach ident : [
-                'archive_entry_gid_is_set',      # since 3.7.3
-                'archive_entry_uid_is_set',      # since 3.7.3
-                'archive_entry_hardlink_is_set', # since 3.7.5
-        ]
-
-        have = libarchive.found() and cc.has_function(ident, dependencies : libarchive)
-        conf.set10('HAVE_' + ident.to_upper(), have)
-endforeach
-
 libxkbcommon = dependency('xkbcommon',
                           version : '>= 0.3.0',
                           required : get_option('xkbcommon'))
index ccf0ec6be3b26b892c9adc92edf554a8fe8412be..0fd78483f854c062b92686f9e3e804430a071369 100644 (file)
@@ -33,6 +33,19 @@ int dlopen_many_sym_or_warn_sentinel(void **dlp, const char *filename, int log_l
 #define DLSYM_ARG_FORCE(arg) \
         &sym_##arg, STRINGIFY(arg)
 
+/* Resolve a single optional symbol from an already-opened library handle. The pointer variable is expected
+ * to be named sym_<name> (same convention as DLSYM_ARG). Only assigns on success, so the pointer keeps its
+ * pre-existing value if the symbol is not present — useful for fallback initialization. dlerror() is
+ * cleared first so callers can distinguish "symbol not found" from "symbol's value is NULL" by checking
+ * dlerror() after; for function symbols (which can never be NULL on success) the _v check below is
+ * sufficient. */
+#define DLSYM_OPTIONAL(dl, name)                                                                \
+        ({                                                                                      \
+                (void) dlerror();                                                               \
+                typeof(sym_##name) _v = (typeof(sym_##name)) dlsym((dl), #name);                \
+                if (_v) sym_##name = _v;                                                        \
+        })
+
 /* If called dlopen_many_sym_or_warn() will fail with EPERM. This can be used to block lazy loading of shared
  * libs, if we transfer a process into a different namespace. Note that this does not work for all calls of
  * dlopen(), just those through our dlopen_safe() wrapper (which we use comprehensively in our
index 697498ea5d4b1c9dfe5bb44f177b958621bdabe0..270c119ab72b3ffadb7ddb0a0c5e101e2a4357a6 100644 (file)
@@ -2047,7 +2047,6 @@ int posix_spawn_wrapper(
         /* Initialization needs to succeed before we can set up a destructor. */
         _unused_ _cleanup_(posix_spawnattr_destroyp) posix_spawnattr_t *attr_destructor = &attr;
 
-#if HAVE_PIDFD_SPAWN
         static bool have_clone_into_cgroup = true; /* kernel 5.7+ */
         _cleanup_close_ int cgroup_fd = -EBADF;
 
@@ -2063,12 +2062,13 @@ int posix_spawn_wrapper(
                         return -errno;
 
                 r = posix_spawnattr_setcgroup_np(&attr, cgroup_fd);
-                if (r != 0)
+                if (r == 0)
+                        flags |= POSIX_SPAWN_SETCGROUP;
+                else if (r != ENOSYS)
                         return -r;
-
-                flags |= POSIX_SPAWN_SETCGROUP;
+                /* If libc lacks posix_spawnattr_setcgroup_np we silently skip POSIX_SPAWN_SETCGROUP — the
+                 * caller will then need to attach the child to the cgroup themselves. */
         }
-#endif
 
         r = posix_spawnattr_setflags(&attr, flags);
         if (r != 0)
@@ -2077,7 +2077,6 @@ int posix_spawn_wrapper(
         if (r != 0)
                 return -r;
 
-#if HAVE_PIDFD_SPAWN
         _cleanup_close_ int pidfd = -EBADF;
 
         r = pidfd_spawn(&pidfd, path, NULL, &attr, argv, envp);
@@ -2101,15 +2100,18 @@ int posix_spawn_wrapper(
 
                 r = pidfd_spawn(&pidfd, path, NULL, &attr, argv, envp);
         }
-        if (r != 0)
+        if (r == 0) {
+                r = pidref_set_pidfd_consume(ret_pidref, TAKE_FD(pidfd));
+                if (r < 0)
+                        return r;
+
+                return FLAGS_SET(flags, POSIX_SPAWN_SETCGROUP);
+        }
+        if (!ERRNO_IS_NOT_SUPPORTED(r))
                 return -r;
 
-        r = pidref_set_pidfd_consume(ret_pidref, TAKE_FD(pidfd));
-        if (r < 0)
-                return r;
+        /* pidfd_spawn unavailable (libc or kernel missing) — fall back to plain posix_spawn. */
 
-        return FLAGS_SET(flags, POSIX_SPAWN_SETCGROUP);
-#else
         pid_t pid;
 
         r = posix_spawn(&pid, path, NULL, &attr, argv, envp);
@@ -2121,7 +2123,6 @@ int posix_spawn_wrapper(
                 return r;
 
         return 0; /* We did not use CLONE_INTO_CGROUP so return 0, the caller will have to move the child */
-#endif
 }
 
 int proc_dir_open(DIR **ret) {
index cb7bb1adcc485b9dd2e478834f1dcd6607fa86fd..bcf38a03c58f5ff359f223bdead5fa4c7615dc7d 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "conf-parser.h"
 #include "coredump-config.h"
+#include "elf-util.h"
 #include "format-util.h"
 #include "journal-def.h"
 #include "log.h"
@@ -45,12 +46,10 @@ int coredump_parse_config(CoredumpConfig *config) {
                 config->journal_size_max = JOURNAL_SIZE_MAX;
         }
 
-#if !HAVE_DWFL_SET_SYSROOT
-        if (config->enter_namespace) {
+        if (config->enter_namespace && !dlopen_dw_has_dwfl_set_sysroot()) {
                 log_warning("EnterNamespace= is enabled but libdw does not support dwfl_set_sysroot(), disabling.");
                 config->enter_namespace = false;
         }
-#endif
 
         log_debug("Selected storage '%s'.", coredump_storage_to_string(config->storage));
         log_debug("Selected compression %s.", yes_no(config->compress));
index 42d92a32e9c6dd23c06900388f7dd7b07b9a5592..f0c961ded7e5f9c4fe8e3f04ccdb2097dc3f1979 100644 (file)
@@ -468,7 +468,9 @@ static int maybe_remove_external_coredump(
 }
 
 static int acquire_pid_mount_tree_fd(const CoredumpConfig *config, CoredumpContext *context) {
-#if HAVE_DWFL_SET_SYSROOT
+        if (!dlopen_dw_has_dwfl_set_sysroot())
+                return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "dwfl_set_sysroot() is not supported.");
+
         _cleanup_close_ int mntns_fd = -EBADF, root_fd = -EBADF, fd = -EBADF;
         _cleanup_close_pair_ int pair[2] = EBADF_PAIR;
         int r;
@@ -533,10 +535,6 @@ static int acquire_pid_mount_tree_fd(const CoredumpConfig *config, CoredumpConte
 
         context->mount_tree_fd = TAKE_FD(fd);
         return 0;
-#else
-        /* Don't bother preparing environment if we can't pass it to libdwfl. */
-        return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "dwfl_set_sysroot() is not supported.");
-#endif
 }
 
 static int attach_mount_tree(const CoredumpConfig *config, CoredumpContext *context) {
index bf313340bf6c20725d705146af526928935997f4..fffecd35738cbc4df9b19172692305630a3c0811 100644 (file)
@@ -608,7 +608,6 @@ static int parse_one_option(const char *option) {
                         log_warning_errno(r, "Failed to parse %s, ignoring: %m", option);
 
         } else if ((val = startswith(option, "link-volume-key="))) {
-#if HAVE_CRYPT_SET_KEYRING_TO_LINK
                 _cleanup_free_ char *keyring = NULL, *key_type = NULL, *key_description = NULL;
                 const char *sep;
 
@@ -657,9 +656,6 @@ static int parse_one_option(const char *option) {
                 free_and_replace(arg_link_keyring, keyring);
                 free_and_replace(arg_link_key_type, key_type);
                 free_and_replace(arg_link_key_description, key_description);
-#else
-                log_error("Build lacks libcryptsetup support for linking volume keys in user specified kernel keyrings upon device activation, ignoring: %s", option);
-#endif
         } else if ((val = startswith(option, "fixate-volume-key="))) {
                 r = free_and_strdup(&arg_fixate_volume_key, val);
                 if (r < 0)
@@ -2688,14 +2684,14 @@ static int verb_attach(int argc, char *argv[], uintptr_t _data, void *userdata)
                 if (r < 0)
                         return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", sym_crypt_get_device_name(cd));
 
-/* since cryptsetup 2.7.0 (Jan 2024) */
-#if HAVE_CRYPT_SET_KEYRING_TO_LINK
+                /* since cryptsetup 2.7.0 (Jan 2024) */
                 if (arg_link_key_description) {
                         r = sym_crypt_set_keyring_to_link(cd, arg_link_key_description, NULL, arg_link_key_type, arg_link_keyring);
-                        if (r < 0)
+                        if (r == -ENOSYS)
+                                log_warning("Loaded libcryptsetup does not support linking volume keys in user specified kernel keyrings upon device activation, ignoring.");
+                        else if (r < 0)
                                 log_warning_errno(r, "Failed to set keyring or key description to link volume key in, ignoring: %m");
                 }
-#endif
 
                 if (arg_header) {
                         r = sym_crypt_set_data_device(cd, source);
index 2ff95e952a4c26e33343eceb19c8526bb9680792..54ad9ed110432bca32b5e90ec5fe5f82949272d9 100644 (file)
@@ -3,15 +3,15 @@
 
 #include_next <stdio.h>
 
-#if !HAVE_RENAMEAT2
+#ifndef RENAME_NOREPLACE
 #  define RENAME_NOREPLACE (1 << 0)
 #  define RENAME_EXCHANGE  (1 << 1)
 #  define RENAME_WHITEOUT  (1 << 2)
-
-int missing_renameat2(int __oldfd, const char *__old, int __newfd, const char *__new, unsigned __flags);
-#  define renameat2 missing_renameat2
 #endif
 
+int renameat2_shim(int __oldfd, const char *__old, int __newfd, const char *__new, unsigned __flags);
+#define renameat2 renameat2_shim
+
 /* When a stream is opened read-only under glibc, fputs() and friends fail with EBADF. However, they
  * succeed under musl. We rely on the glibc behavior in the code base. The following _check_writable()
  * functions first check if the passed stream is writable, and refuse to write with EBADF if not. */
index a6f2afe53b8108e6913f24a45eb587d56a296adb..875f112b009d1d2739a01d85fbf2086ed581c7aa 100644 (file)
@@ -27,7 +27,5 @@
 
 /* Defined since glibc-2.42.
  * Supported since kernel v5.6 (fddb5d430ad9fa91b49b1d34d0202ffe2fa0e179). */
-#if !HAVE_OPENAT2
-int missing_openat2(int dfd, const char *filename, const struct open_how *how, size_t usize);
-#  define openat2 missing_openat2
-#endif
+int openat2_shim(int dfd, const char *filename, const struct open_how *how, size_t usize);
+#define openat2 openat2_shim
index 08f4576eca1e322ee404f046bb15a2cbf8b7d085..3eed39311868ead35bdf71a18466e4a3f4e8b70e 100644 (file)
@@ -51,10 +51,8 @@ int __clone2(int (*fn)(void *), void *stack_base, size_t stack_size, int flags,
 
 /* Defined since glibc-2.41.
  * Supported since kernel 3.14 (e6cfc0295c7d51b008999a8b13a44fb43f8685ea). */
-#if !HAVE_SCHED_SETATTR
-int missing_sched_setattr(pid_t pid, struct sched_attr *attr, unsigned flags);
-#  define sched_setattr missing_sched_setattr
-#endif
+int sched_setattr_shim(pid_t pid, struct sched_attr *attr, unsigned flags);
+#define sched_setattr sched_setattr_shim
 
 /* f0e1a0643a59bf1f922fa209cec86a170b784f3f (6.12),
  * defined in sched.h in glibc since glibc-2.41. */
index 436b49a51999367d22038552df1d0345b0599afc..6e596adaccef2a1bd2ac8379a27835062bd5811a 100644 (file)
@@ -3,7 +3,5 @@
 
 #include_next <signal.h>        /* IWYU pragma: export */
 
-#if !HAVE_RT_TGSIGQUEUEINFO
-int missing_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *info);
-#  define rt_tgsigqueueinfo missing_rt_tgsigqueueinfo
-#endif
+int rt_tgsigqueueinfo_shim(pid_t tgid, pid_t tid, int sig, siginfo_t *info);
+#define rt_tgsigqueueinfo rt_tgsigqueueinfo_shim
diff --git a/src/include/override/spawn.h b/src/include/override/spawn.h
new file mode 100644 (file)
index 0000000..4638258
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include_next <spawn.h>        /* IWYU pragma: export */
+
+/* pidfd_spawn() and posix_spawnattr_setcgroup_np() were added in glibc 2.39. Redirect to shims that
+ * return ENOSYS at runtime when the libc symbols aren't available, so callers don't need to worry
+ * about the libc version. */
+int pidfd_spawn_shim(pid_t *restrict pidfd, const char *restrict path,
+                     const posix_spawn_file_actions_t *restrict file_actions,
+                     const posix_spawnattr_t *restrict attrp,
+                     char *const argv[restrict], char *const envp[restrict]);
+#define pidfd_spawn pidfd_spawn_shim
+
+int posix_spawnattr_setcgroup_np_shim(posix_spawnattr_t *attr, int cgroup);
+#define posix_spawnattr_setcgroup_np posix_spawnattr_setcgroup_np_shim
+
+/* Defined in <spawn.h> since glibc 2.39. */
+#ifndef POSIX_SPAWN_SETCGROUP
+#  define POSIX_SPAWN_SETCGROUP 0x100
+#endif
index 56e1466b89006ed81e3d9907a7697fb41a4288f1..eaeb89a5a8fb6b7d3a23032fe41fa89bda5a4cbc 100644 (file)
@@ -5,7 +5,5 @@
 #include <stddef.h>
 
 /* Supported since kernel v3.18 (749730ce42a2121e1c88350d69478bff3994b10a). */
-#if !HAVE_BPF
-int missing_bpf(int cmd, union bpf_attr *attr, size_t size);
-#  define bpf missing_bpf
-#endif
+int bpf_shim(int cmd, union bpf_attr *attr, size_t size);
+#define bpf bpf_shim
diff --git a/src/include/override/sys/epoll.h b/src/include/override/sys/epoll.h
new file mode 100644 (file)
index 0000000..0ed9c27
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include_next <sys/epoll.h>     /* IWYU pragma: export */
+
+/* epoll_pwait2() was added to glibc 2.35. Redirect to a shim that sets errno=ENOSYS at runtime when
+ * the libc symbol isn't available, so callers don't need to worry about the libc version. */
+int epoll_pwait2_shim(int fd, struct epoll_event *events, int maxevents,
+                      const struct timespec *timeout, const sigset_t *sigmask);
+#define epoll_pwait2 epoll_pwait2_shim
index c361eba6e6071738c2db4e95463eba6386f495c2..8ea4c8f8b2a86ad1df1c0fceacc66748915fdfc9 100644 (file)
@@ -3,12 +3,8 @@
 
 #include <linux/ioprio.h>       /* IWYU pragma: export */
 
-#if !HAVE_IOPRIO_GET
-int missing_ioprio_get(int which, int who);
-#  define ioprio_get missing_ioprio_get
-#endif
+int ioprio_get_shim(int which, int who);
+#define ioprio_get ioprio_get_shim
 
-#if !HAVE_IOPRIO_SET
-int missing_ioprio_set(int which, int who, int ioprio);
-#  define ioprio_set missing_ioprio_set
-#endif
+int ioprio_set_shim(int which, int who, int ioprio);
+#define ioprio_set ioprio_set_shim
index 4e47825ac5b41cace254eb31cbc87d7be169a13c..f0df5d402017bedf2cbcdd8e624e36ecb7c3ab64 100644 (file)
@@ -5,7 +5,5 @@
 #include <sys/types.h>
 
 /* Supported since kernel v3.5 (d97b46a64674a267bc41c9e16132ee2a98c3347d). */
-#if !HAVE_KCMP
-int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2);
-#  define kcmp missing_kcmp
-#endif
+int kcmp_shim(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2);
+#define kcmp kcmp_shim
index 4e256bdb6ad385701f0e3afa5318818b81fb349b..be31c93520ef08e4c3e85213630bfbb67b62d441 100644 (file)
@@ -6,11 +6,9 @@
 
 /* Supported since kernel v3.17 (cb1052581e2bddd6096544f3f944f4e7fdad4c4f).
  * Not available on all architectures. */
-#if HAVE_KEXEC_FILE_LOAD || defined __NR_kexec_file_load
-#  if !HAVE_KEXEC_FILE_LOAD
-int missing_kexec_file_load(int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char *cmdline, unsigned long flags);
-#    define kexec_file_load missing_kexec_file_load
-#  endif
+#ifdef __NR_kexec_file_load
+int kexec_file_load_shim(int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char *cmdline, unsigned long flags);
+#  define kexec_file_load kexec_file_load_shim
 #  define HAVE_KEXEC_FILE_LOAD_SYSCALL 1
 #else
 #  define HAVE_KEXEC_FILE_LOAD_SYSCALL 0
index 88c9c40ea78be00785c78fb4a3a0575d9fecb059..65be2fea2deeeef492b49aec1c479901b9387b9e 100644 (file)
@@ -4,17 +4,11 @@
 #include <linux/keyctl.h>       /* IWYU pragma: export */
 #include <stddef.h>
 
-#if !HAVE_KEYCTL
-long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
-#  define keyctl missing_keyctl
-#endif
+long keyctl_shim(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
+#define keyctl keyctl_shim
 
-#if !HAVE_ADD_KEY
-key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid);
-#  define add_key missing_add_key
-#endif
+key_serial_t add_key_shim(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid);
+#define add_key add_key_shim
 
-#if !HAVE_REQUEST_KEY
-key_serial_t missing_request_key(const char *type, const char *description, const char *callout_info, key_serial_t destringid);
-#  define request_key missing_request_key
-#endif
+key_serial_t request_key_shim(const char *type, const char *description, const char *callout_info, key_serial_t destringid);
+#define request_key request_key_shim
index 9858f2812bef73f2f796ed57ab25092654c92915..1ba6d95958bbed2c7c9e5ba80685af3690042b54 100644 (file)
@@ -3,12 +3,8 @@
 
 #include <linux/mempolicy.h>    /* IWYU pragma: export */
 
-#if !HAVE_SET_MEMPOLICY
-int missing_set_mempolicy(int mode, const unsigned long *nodemask, unsigned long maxnode);
-#  define set_mempolicy missing_set_mempolicy
-#endif
+int set_mempolicy_shim(int mode, const unsigned long *nodemask, unsigned long maxnode);
+#define set_mempolicy set_mempolicy_shim
 
-#if !HAVE_GET_MEMPOLICY
-int missing_get_mempolicy(int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags);
-#  define get_mempolicy missing_get_mempolicy
-#endif
+int get_mempolicy_shim(int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags);
+#define get_mempolicy get_mempolicy_shim
index e6d7ad1b67c74ea9efd2006fc913f58c0329d7ef..2fa5c902e5bcf7ecdcec128cd22ded936a349e07 100644 (file)
@@ -39,56 +39,36 @@ extern int umount2(const char *__special_file, int __flags);
 /* Open the filesystem referenced by FS_NAME so it can be configured for mounting. */
 /* Defined since glibc-2.36.
  * Supported since kernel v5.2 (24dcb3d90a1f67fe08c68a004af37df059d74005). */
-#if HAVE_FSOPEN
-extern int fsopen(const char *__fs_name, unsigned int __flags);
-#else
-int missing_fsopen(const char *fsname, unsigned flags);
-#  define fsopen missing_fsopen
-#endif
+int fsopen_shim(const char *fsname, unsigned flags);
+#define fsopen fsopen_shim
 
 /* Create a mount representation for the FD created by fsopen using
    FLAGS with ATTR_FLAGS describing how the mount is to be performed.  */
 /* Defined since glibc-2.36.
  * Supported since kernel v5.2 (93766fbd2696c2c4453dd8e1070977e9cd4e6b6d). */
-#if HAVE_FSMOUNT
-extern int fsmount(int __fd, unsigned int __flags, unsigned int __ms_flags);
-#else
-int missing_fsmount(int fd, unsigned flags, unsigned ms_flags);
-#  define fsmount missing_fsmount
-#endif
+int fsmount_shim(int fd, unsigned flags, unsigned ms_flags);
+#define fsmount fsmount_shim
 
 /* Add the mounted FROM_DFD referenced by FROM_PATHNAME filesystem returned
    by fsmount in the hierarchy in the place TO_DFD reference by TO_PATHNAME
    using FLAGS.  */
 /* Defined since glibc-2.36.
  * Supported since kernel v5.2 (2db154b3ea8e14b04fee23e3fdfd5e9d17fbc6ae). */
-#if HAVE_MOVE_MOUNT
-extern int move_mount(int __from_dfd, const char *__from_pathname, int __to_dfd, const char *__to_pathname, unsigned int flags);
-#else
-int missing_move_mount(int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, unsigned flags);
-#  define move_mount missing_move_mount
-#endif
+int move_mount_shim(int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, unsigned flags);
+#define move_mount move_mount_shim
 
 /* Set parameters and trigger CMD action on the FD context.  KEY, VALUE,
    and AUX are used depending ng of the CMD.  */
 /* Defined since glibc-2.36.
  * Supported since kernel v5.2 (ecdab150fddb42fe6a739335257949220033b782). */
-#if HAVE_FSCONFIG
-extern int fsconfig(int __fd, unsigned int __cmd, const char *__key, const void *__value, int __aux);
-#else
-int missing_fsconfig(int fd, unsigned cmd, const char *key, const void *value, int aux);
-#  define fsconfig missing_fsconfig
-#endif
+int fsconfig_shim(int fd, unsigned cmd, const char *key, const void *value, int aux);
+#define fsconfig fsconfig_shim
 
 /* Open the mount point FILENAME in directory DFD using FLAGS.  */
 /* Defined since glibc-2.36.
  * Supported since kernel v5.2 (a07b20004793d8926f78d63eb5980559f7813404). */
-#if HAVE_OPEN_TREE
-extern int open_tree(int __dfd, const char *__filename, unsigned int __flags);
-#else
-int missing_open_tree(int dfd, const char *filename, unsigned flags);
-#  define open_tree missing_open_tree
-#endif
+int open_tree_shim(int dfd, const char *filename, unsigned flags);
+#define open_tree open_tree_shim
 
 /* Change the mount properties of the mount or an entire mount tree.  If
    PATH is a relative pathname, then it is interpreted relative to the
@@ -97,18 +77,10 @@ int missing_open_tree(int dfd, const char *filename, unsigned flags);
    working directory of the calling process.  */
 /* Defined since glibc-2.36.
  * Supported since kernel v5.12 (2a1867219c7b27f928e2545782b86daaf9ad50bd). */
-#if HAVE_MOUNT_SETATTR
-extern int mount_setattr(int __dfd, const char *__path, unsigned int __flags, struct mount_attr *__uattr, size_t __usize);
-#else
-int missing_mount_setattr(int dfd, const char *path, unsigned flags, struct mount_attr *attr, size_t size);
-#  define mount_setattr missing_mount_setattr
-#endif
+int mount_setattr_shim(int dfd, const char *path, unsigned flags, struct mount_attr *attr, size_t size);
+#define mount_setattr mount_setattr_shim
 
 /* Not defined in glibc yet as of glibc-2.41.
  * Supported since kernel v6.15 (c4a16820d90199409c9bf01c4f794e1e9e8d8fd8). */
-#if HAVE_OPEN_TREE_ATTR
-extern int open_tree_attr(int __dfd, const char *__filename, unsigned int __flags, struct mount_attr *__uattr, size_t __usize);
-#else
-int missing_open_tree_attr(int dfd, const char *filename, unsigned int flags, struct mount_attr *attr, size_t size);
-#  define open_tree_attr missing_open_tree_attr
-#endif
+int open_tree_attr_shim(int dfd, const char *filename, unsigned int flags, struct mount_attr *attr, size_t size);
+#define open_tree_attr open_tree_attr_shim
index 7f136eb62eeb7bb9fea9363f383167c818010326..0e9b2f39989d7ba15b517e0fe9e058b8e95b50cd 100644 (file)
@@ -1,8 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-/* since glibc-2.36 */
-#if HAVE_PIDFD_OPEN
+#include <features.h>
+
+/* since glibc-2.36. Only descend into the next <sys/pidfd.h> on glibc — musl ships no such header,
+ * and musl-gcc's -idirafter /usr/include would otherwise pull in glibc's copy (which depends on
+ * __THROW and other glibc-isms) from the fallback path. */
+#if defined(__GLIBC__) && __has_include_next(<sys/pidfd.h>)
 #include_next <sys/pidfd.h>     /* IWYU pragma: export */
 #endif
 
 
 /* Defined since glibc-2.36.
  * Supported since kernel v5.3 (7615d9e1780e26e0178c93c55b73309a5dc093d7). */
-#if !HAVE_PIDFD_OPEN
-int missing_pidfd_open(pid_t pid, unsigned flags);
-#  define pidfd_open missing_pidfd_open
-#endif
+int pidfd_open_shim(pid_t pid, unsigned flags);
+#define pidfd_open pidfd_open_shim
 
 /* Defined since glibc-2.36.
  * Supported since kernel v5.1 (3eb39f47934f9d5a3027fe00d906a45fe3a15fad). */
-#if !HAVE_PIDFD_SEND_SIGNAL
-int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags);
-#  define pidfd_send_signal missing_pidfd_send_signal
-#endif
+int pidfd_send_signal_shim(int fd, int sig, siginfo_t *info, unsigned flags);
+#define pidfd_send_signal pidfd_send_signal_shim
 
 /* since glibc-2.41 */
 #ifndef PIDFS_IOCTL_MAGIC
index fcf6be988bb24cc63cefdbd7033fbfa793e18dc1..95aa3674460e1efa7b7f1a3f83b4ac4890348bb2 100644 (file)
@@ -4,7 +4,5 @@
 #include_next <sys/quota.h>     /* IWYU pragma: export */
 
 /* Supported since kernel v5.14 (64c2c2c62f92339b176ea24403d8db16db36f9e6). */
-#if !HAVE_QUOTACTL_FD
-int missing_quotactl_fd(int fd, int cmd, int id, void *addr);
-#  define quotactl_fd missing_quotactl_fd
-#endif
+int quotactl_fd_shim(int fd, int cmd, int id, void *addr);
+#define quotactl_fd quotactl_fd_shim
index 5cef9f852ee0ba9dd756d940a923bea05aa95b7a..bfd9b54e7f90ed308f4e9f78329241926a0cdb69 100644 (file)
@@ -4,7 +4,5 @@
 #include_next <sys/stat.h>      /* IWYU pragma: export */
 
 /* Supported since kernel v6.6 (78252deb023cf0879256fcfbafe37022c390762b). */
-#if !HAVE_FCHMODAT2
-int missing_fchmodat2(int dirfd, const char *path, mode_t mode, int flags);
-#  define fchmodat2 missing_fchmodat2
-#endif
+int fchmodat2_shim(int dirfd, const char *path, mode_t mode, int flags);
+#define fchmodat2 fchmodat2_shim
index db31d0ba6f3e40795ca89a37532396df5ab7a405..8823548d89d03c9031bb36559fde93a99df72321 100644 (file)
@@ -8,13 +8,9 @@
 #include_next <sys/xattr.h>     /* IWYU pragma: export */
 
 /* Supported since kernel v6.13 (6140be90ec70c39fa844741ca3cc807dd0866394). */
-#if !HAVE_SETXATTRAT
-int missing_setxattrat(int fd, const char *path, int at_flags, const char *name, const struct xattr_args *args, size_t size);
-#  define setxattrat missing_setxattrat
-#endif
+int setxattrat_shim(int fd, const char *path, int at_flags, const char *name, const struct xattr_args *args, size_t size);
+#define setxattrat setxattrat_shim
 
 /* Supported since kernel v6.13 (6140be90ec70c39fa844741ca3cc807dd0866394). */
-#if !HAVE_REMOVEXATTRAT
-int missing_removexattrat(int fd, const char *path, int at_flags, const char *name);
-#  define removexattrat missing_removexattrat
-#endif
+int removexattrat_shim(int fd, const char *path, int at_flags, const char *name);
+#define removexattrat removexattrat_shim
index bd558694eebddbcf68f6d90fc66b5306eb7672e0..7dd56aa06f6a14a21902fe9daa7eeacc67bad3ea 100644 (file)
@@ -3,7 +3,5 @@
 
 #include_next <unistd.h>        /* IWYU pragma: export */
 
-#if !HAVE_PIVOT_ROOT
-int missing_pivot_root(const char *new_root, const char *put_old);
-#  define pivot_root missing_pivot_root
-#endif
+int pivot_root_shim(const char *new_root, const char *put_old);
+#define pivot_root pivot_root_shim
index 4a7498e502aa70873c3388600162248eed0c083d..d87dcb1b0c1cf51336789b66f70742f06b7b6326 100644 (file)
@@ -1,11 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/bpf.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_BPF
-int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
-        return syscall(__NR_bpf, cmd, attr, size);
-}
-#endif
+#include "libc-shim.h"
+
+DEFINE_SYSCALL_SHIM(bpf, int,
+                    int, cmd,
+                    union bpf_attr *, attr,
+                    size_t, size)
diff --git a/src/libc/epoll.c b/src/libc/epoll.c
new file mode 100644 (file)
index 0000000..0845cf3
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <sys/epoll.h>
+
+#include "libc-shim.h"
+
+DEFINE_LIBC_ERRNO_SHIM(epoll_pwait2, int,
+                       int, fd,
+                       struct epoll_event *, events,
+                       int, maxevents,
+                       const struct timespec *, timeout,
+                       const sigset_t *, sigmask)
index ca5e6c7977c04558be673a766acaeb1ccc6af580..8fd78ca897e5e3a67d1fadfd8a2b6ac200caffde 100644 (file)
@@ -1,11 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <fcntl.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_OPENAT2
-int missing_openat2(int dfd, const char *filename, const struct open_how *how, size_t usize) {
-        return syscall(__NR_openat2, dfd, filename, how, usize);
-}
-#endif
+#include "libc-shim.h"
+
+DEFINE_SYSCALL_SHIM(openat2, int,
+                    int, dfd,
+                    const char *, filename,
+                    const struct open_how *, how,
+                    size_t, usize)
index 5bb640457dc1f99250ee2f58121c2567b3800e7a..053693139c3b55b6a927087e453a3281b29a0b42 100644 (file)
@@ -1,17 +1,14 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/ioprio.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_IOPRIO_GET
-int missing_ioprio_get(int which, int who) {
-        return syscall(__NR_ioprio_get, which, who);
-}
-#endif
+#include "libc-shim.h"
 
-#if !HAVE_IOPRIO_SET
-int missing_ioprio_set(int which, int who, int ioprio) {
-        return syscall(__NR_ioprio_set, which, who, ioprio);
-}
-#endif
+DEFINE_SYSCALL_SHIM(ioprio_get, int,
+                    int, which,
+                    int, who)
+
+DEFINE_SYSCALL_SHIM(ioprio_set, int,
+                    int, which,
+                    int, who,
+                    int, ioprio)
index aafff999ef44a35c948f63a938587e782861c30a..0f73f8500dd620ec3e78954d52cd51ed291e26d6 100644 (file)
@@ -1,11 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/kcmp.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_KCMP
-int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
-        return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
-}
-#endif
+#include "libc-shim.h"
+
+DEFINE_SYSCALL_SHIM(kcmp, int,
+                    pid_t, pid1,
+                    pid_t, pid2,
+                    int, type,
+                    unsigned long, idx1,
+                    unsigned long, idx2)
index 122acff956c07b4677ed765468e3ed2a40cf2795..051253d17bde8bb05e20022582ed62ae3b3db6b4 100644 (file)
@@ -1,11 +1,14 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/kexec.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_KEXEC_FILE_LOAD && defined __NR_kexec_file_load
-int missing_kexec_file_load(int kernel_fd, int initrd_fd, unsigned long cmdline_len, const char *cmdline, unsigned long flags) {
-        return syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len, cmdline, flags);
-}
+#include "libc-shim.h"
+
+#ifdef __NR_kexec_file_load
+DEFINE_SYSCALL_SHIM(kexec_file_load, int,
+                    int, kernel_fd,
+                    int, initrd_fd,
+                    unsigned long, cmdline_len,
+                    const char *, cmdline,
+                    unsigned long, flags)
 #endif
index af4bca87f513e655bf9563b9f598e307fb921fe2..c86518454835bbcd5b864eb2deb754df8ca713e1 100644 (file)
@@ -1,23 +1,25 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/keyctl.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_KEYCTL
-long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) {
-        return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
-}
-#endif
+#include "libc-shim.h"
 
-#if !HAVE_ADD_KEY
-key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) {
-        return syscall(__NR_add_key, type, description, payload, plen, ringid);
-}
-#endif
+DEFINE_SYSCALL_SHIM(keyctl, long,
+                    int, cmd,
+                    unsigned long, arg2,
+                    unsigned long, arg3,
+                    unsigned long, arg4,
+                    unsigned long, arg5)
 
-#if !HAVE_REQUEST_KEY
-key_serial_t missing_request_key(const char *type, const char *description, const char *callout_info, key_serial_t destringid) {
-        return syscall(__NR_request_key, type, description, callout_info, destringid);
-}
-#endif
+DEFINE_SYSCALL_SHIM(add_key, key_serial_t,
+                    const char *, type,
+                    const char *, description,
+                    const void *, payload,
+                    size_t, plen,
+                    key_serial_t, ringid)
+
+DEFINE_SYSCALL_SHIM(request_key, key_serial_t,
+                    const char *, type,
+                    const char *, description,
+                    const char *, callout_info,
+                    key_serial_t, destringid)
diff --git a/src/libc/libc-shim.h b/src/libc/libc-shim.h
new file mode 100644 (file)
index 0000000..c5cf9c8
--- /dev/null
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <errno.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+/* Each parameter is passed as a flat (type, name) pair: type1, name1, type2, name2, ... The
+ * _SHIM_DECL/_SHIM_NAME macros consume two args at a time and emit either "type name" pairs (for
+ * the function declarator) or just the names (for forwarding). _SHIM_PAIRS counts the number of
+ * pairs by indexing into a table that increments every two positions. */
+#define _SHIM_CAT(a, b) _SHIM_CAT_(a, b)
+#define _SHIM_CAT_(a, b) a##b
+
+#define _SHIM_NTH(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
+#define _SHIM_PAIRS(...) _SHIM_NTH(__VA_ARGS__, 8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0)
+
+#define _SHIM_DECL_1(t, n)      t n
+#define _SHIM_DECL_2(t, n, ...) t n, _SHIM_DECL_1(__VA_ARGS__)
+#define _SHIM_DECL_3(t, n, ...) t n, _SHIM_DECL_2(__VA_ARGS__)
+#define _SHIM_DECL_4(t, n, ...) t n, _SHIM_DECL_3(__VA_ARGS__)
+#define _SHIM_DECL_5(t, n, ...) t n, _SHIM_DECL_4(__VA_ARGS__)
+#define _SHIM_DECL_6(t, n, ...) t n, _SHIM_DECL_5(__VA_ARGS__)
+#define _SHIM_DECL_7(t, n, ...) t n, _SHIM_DECL_6(__VA_ARGS__)
+#define _SHIM_DECL_8(t, n, ...) t n, _SHIM_DECL_7(__VA_ARGS__)
+#define _SHIM_DECL(...) _SHIM_CAT(_SHIM_DECL_, _SHIM_PAIRS(__VA_ARGS__))(__VA_ARGS__)
+
+#define _SHIM_NAME_1(t, n)      n
+#define _SHIM_NAME_2(t, n, ...) n, _SHIM_NAME_1(__VA_ARGS__)
+#define _SHIM_NAME_3(t, n, ...) n, _SHIM_NAME_2(__VA_ARGS__)
+#define _SHIM_NAME_4(t, n, ...) n, _SHIM_NAME_3(__VA_ARGS__)
+#define _SHIM_NAME_5(t, n, ...) n, _SHIM_NAME_4(__VA_ARGS__)
+#define _SHIM_NAME_6(t, n, ...) n, _SHIM_NAME_5(__VA_ARGS__)
+#define _SHIM_NAME_7(t, n, ...) n, _SHIM_NAME_6(__VA_ARGS__)
+#define _SHIM_NAME_8(t, n, ...) n, _SHIM_NAME_7(__VA_ARGS__)
+#define _SHIM_NAME(...) _SHIM_CAT(_SHIM_NAME_, _SHIM_PAIRS(__VA_ARGS__))(__VA_ARGS__)
+
+/* Defines a wrapper that calls the libc symbol if available at runtime, or falls back to the
+ * corresponding direct syscall otherwise. The libc symbol is redeclared as a weak reference so the
+ * binary still loads on libc versions that don't provide it. Each parameter is passed as type,
+ * name pairs (flat).
+ *
+ * The weak reference is bound to the libc symbol via an __asm__("label") rename so that the bare
+ * libc identifier never appears as a C token. This matters because override/musl headers
+ * sometimes #define the libc name to redirect it to the _shim variant — without the rename the
+ * caller would have to #undef each name before invoking the macro. # and ## operators don't
+ * macro-expand their operands, so the parameter "func" stays a literal token everywhere. */
+#define DEFINE_SYSCALL_SHIM(func, ret, ...)                                                          \
+        extern typeof(func##_shim) func##_libc_weak __asm__(#func) __attribute__((__weak__));        \
+        ret func##_shim(_SHIM_DECL(__VA_ARGS__)) {                                                   \
+                if (func##_libc_weak)                                                                \
+                        return func##_libc_weak(_SHIM_NAME(__VA_ARGS__));                            \
+                return syscall(__NR_##func, _SHIM_NAME(__VA_ARGS__));                                \
+        }
+
+/* Like DEFINE_SYSCALL_SHIM but for libc helpers that have no corresponding syscall and report errors
+ * by returning the positive errno value directly (posix_spawn-family convention). If the libc symbol
+ * is missing at runtime, ENOSYS is returned. */
+#define DEFINE_LIBC_SHIM(func, ret, ...)                                                             \
+        extern typeof(func##_shim) func##_libc_weak __asm__(#func) __attribute__((__weak__));        \
+        ret func##_shim(_SHIM_DECL(__VA_ARGS__)) {                                                   \
+                if (func##_libc_weak)                                                                \
+                        return func##_libc_weak(_SHIM_NAME(__VA_ARGS__));                            \
+                return ENOSYS;                                                                       \
+        }
+
+/* Like DEFINE_LIBC_SHIM but for libc helpers that report errors via errno + -1 return value. If the
+ * libc symbol is missing at runtime, errno is set to ENOSYS and -1 is returned. */
+#define DEFINE_LIBC_ERRNO_SHIM(func, ret, ...)                                                       \
+        extern typeof(func##_shim) func##_libc_weak __asm__(#func) __attribute__((__weak__));        \
+        ret func##_shim(_SHIM_DECL(__VA_ARGS__)) {                                                   \
+                if (func##_libc_weak)                                                                \
+                        return func##_libc_weak(_SHIM_NAME(__VA_ARGS__));                            \
+                errno = ENOSYS;                                                                      \
+                return -1;                                                                           \
+        }
index 77b0e1ac010f9b968d99edaac310bbb314095547..686aba2b59024430a852c35ee8c964f7109f3385 100644 (file)
@@ -1,17 +1,17 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/mempolicy.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_SET_MEMPOLICY
-int missing_set_mempolicy(int mode, const unsigned long *nodemask, unsigned long maxnode) {
-        return syscall(__NR_set_mempolicy, mode, nodemask, maxnode);
-}
-#endif
+#include "libc-shim.h"
 
-#if !HAVE_GET_MEMPOLICY
-int missing_get_mempolicy(int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags) {
-        return syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags);
-}
-#endif
+DEFINE_SYSCALL_SHIM(set_mempolicy, int,
+                    int, mode,
+                    const unsigned long *, nodemask,
+                    unsigned long, maxnode)
+
+DEFINE_SYSCALL_SHIM(get_mempolicy, int,
+                    int *, mode,
+                    unsigned long *, nodemask,
+                    unsigned long, maxnode,
+                    void *, addr,
+                    unsigned long, flags)
index e100a6f4ea06dce3f6b2243904826bcd9d433109..9b86168536e439088710d31599e6785f14e1822c 100644 (file)
@@ -2,6 +2,7 @@
 
 libc_wrapper_sources = files(
         'bpf.c',
+        'epoll.c',
         'fcntl.c',
         'ioprio.c',
         'kcmp.c',
@@ -13,6 +14,7 @@ libc_wrapper_sources = files(
         'quota.c',
         'sched.c',
         'signal.c',
+        'spawn.c',
         'stat.c',
         'unistd.c',
         'xattr.c',
index 1d324ef386614a943e605ca67895dd5582a4d2ed..3e626e87acd2bf79d00186967e14c6274fd3c594 100644 (file)
@@ -1,47 +1,47 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/mount.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#if !HAVE_FSOPEN
-int missing_fsopen(const char *fsname, unsigned flags) {
-        return syscall(__NR_fsopen, fsname, flags);
-}
-#endif
-
-#if !HAVE_FSMOUNT
-int missing_fsmount(int fd, unsigned flags, unsigned ms_flags) {
-        return syscall(__NR_fsmount, fd, flags, ms_flags);
-}
-#endif
-
-#if !HAVE_MOVE_MOUNT
-int missing_move_mount(int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, unsigned flags) {
-        return syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd, to_pathname, flags);
-}
-#endif
-
-#if !HAVE_FSCONFIG
-int missing_fsconfig(int fd, unsigned cmd, const char *key, const void *value, int aux) {
-        return syscall(__NR_fsconfig, fd, cmd, key, value, aux);
-}
-#endif
-
-#if !HAVE_OPEN_TREE
-int missing_open_tree(int dfd, const char *filename, unsigned flags) {
-        return syscall(__NR_open_tree, dfd, filename, flags);
-}
-#endif
-
-#if !HAVE_MOUNT_SETATTR
-int missing_mount_setattr(int dfd, const char *path, unsigned flags, struct mount_attr *attr, size_t size) {
-        return syscall(__NR_mount_setattr, dfd, path, flags, attr, size);
-}
-#endif
-
-#if !HAVE_OPEN_TREE_ATTR
-int missing_open_tree_attr(int dfd, const char *filename, unsigned int flags, struct mount_attr *attr, size_t size) {
-        return syscall(__NR_open_tree_attr, dfd, filename, flags, attr, size);
-}
-#endif
+
+#include "libc-shim.h"
+
+DEFINE_SYSCALL_SHIM(fsopen, int,
+                    const char *, fsname,
+                    unsigned, flags)
+
+DEFINE_SYSCALL_SHIM(fsmount, int,
+                    int, fd,
+                    unsigned, flags,
+                    unsigned, ms_flags)
+
+DEFINE_SYSCALL_SHIM(move_mount, int,
+                    int, from_dfd,
+                    const char *, from_pathname,
+                    int, to_dfd,
+                    const char *, to_pathname,
+                    unsigned, flags)
+
+DEFINE_SYSCALL_SHIM(fsconfig, int,
+                    int, fd,
+                    unsigned, cmd,
+                    const char *, key,
+                    const void *, value,
+                    int, aux)
+
+DEFINE_SYSCALL_SHIM(open_tree, int,
+                    int, dfd,
+                    const char *, filename,
+                    unsigned, flags)
+
+DEFINE_SYSCALL_SHIM(mount_setattr, int,
+                    int, dfd,
+                    const char *, path,
+                    unsigned, flags,
+                    struct mount_attr *, attr,
+                    size_t, size)
+
+DEFINE_SYSCALL_SHIM(open_tree_attr, int,
+                    int, dfd,
+                    const char *, filename,
+                    unsigned int, flags,
+                    struct mount_attr *, attr,
+                    size_t, size)
index 6d02aef5f65daae8e63c88aaa2d16d3181056e85..f4e8d9e4c18e7245a72f759fe17bd66623e031ab 100644 (file)
@@ -3,14 +3,15 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdio_ext.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_RENAMEAT2
-int missing_renameat2(int __oldfd, const char *__old, int __newfd, const char *__new, unsigned __flags) {
-        return syscall(__NR_renameat2, __oldfd, __old, __newfd, __new, __flags);
-}
-#endif
+#include "../libc-shim.h"
+
+DEFINE_SYSCALL_SHIM(renameat2, int,
+                    int, __oldfd,
+                    const char *, __old,
+                    int, __newfd,
+                    const char *, __new,
+                    unsigned, __flags)
 
 #define DEFINE_PUT(func)                                         \
         int func##_check_writable(int c, FILE *stream) {         \
index a779e3459c6744b94a186baeccc25dcbfe0e3f92..8343cf7ff9fa9bdfcc2b7a24606727e2d110342e 100644 (file)
@@ -1,17 +1,15 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/pidfd.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_PIDFD_OPEN
-int missing_pidfd_open(pid_t pid, unsigned flags) {
-        return syscall(__NR_pidfd_open, pid, flags);
-}
-#endif
+#include "libc-shim.h"
 
-#if !HAVE_PIDFD_SEND_SIGNAL
-int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
-        return syscall(__NR_pidfd_send_signal, fd, sig, info, flags);
-}
-#endif
+DEFINE_SYSCALL_SHIM(pidfd_open, int,
+                    pid_t, pid,
+                    unsigned, flags)
+
+DEFINE_SYSCALL_SHIM(pidfd_send_signal, int,
+                    int, fd,
+                    int, sig,
+                    siginfo_t *, info,
+                    unsigned, flags)
index 19695df9b3c3209abde78d9613d4954e5c86e4a8..08a7e5b8ae2a16e43b49014a3a77d52c8dcf3172 100644 (file)
@@ -1,11 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/quota.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_QUOTACTL_FD
-int missing_quotactl_fd(int fd, int cmd, int id, void *addr) {
-        return syscall(__NR_quotactl_fd, fd, cmd, id, addr);
-}
-#endif
+#include "libc-shim.h"
+
+DEFINE_SYSCALL_SHIM(quotactl_fd, int,
+                    int, fd,
+                    int, cmd,
+                    int, id,
+                    void *, addr)
index cf1752651b39b1202c9a80e5ade540a72b5c1bcd..24de9731beb61573f9302fa49879345affb3a1d8 100644 (file)
@@ -1,11 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sched.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_SCHED_SETATTR
-int missing_sched_setattr(pid_t pid, struct sched_attr *attr, unsigned flags) {
-        return syscall(__NR_sched_setattr, pid, attr, flags);
-}
-#endif
+#include "libc-shim.h"
+
+DEFINE_SYSCALL_SHIM(sched_setattr, int,
+                    pid_t, pid,
+                    struct sched_attr *, attr,
+                    unsigned, flags)
index 1908331b1a4f2b7e8d05d338441ddc2a45006123..9370491821f82f072c80248e5d5b73f03ae6ef74 100644 (file)
@@ -1,11 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <signal.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_RT_TGSIGQUEUEINFO
-int missing_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *info) {
-        return syscall(__NR_rt_tgsigqueueinfo, tgid, tid, sig, info);
-}
-#endif
+#include "libc-shim.h"
+
+DEFINE_SYSCALL_SHIM(rt_tgsigqueueinfo, int,
+                    pid_t, tgid,
+                    pid_t, tid,
+                    int, sig,
+                    siginfo_t *, info)
diff --git a/src/libc/spawn.c b/src/libc/spawn.c
new file mode 100644 (file)
index 0000000..6e2f9cf
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <spawn.h>
+
+#include "libc-shim.h"
+
+DEFINE_LIBC_SHIM(pidfd_spawn, int,
+                 pid_t *restrict, pidfd,
+                 const char *restrict, path,
+                 const posix_spawn_file_actions_t *restrict, file_actions,
+                 const posix_spawnattr_t *restrict, attrp,
+                 char *const *restrict, argv,
+                 char *const *restrict, envp)
+
+DEFINE_LIBC_SHIM(posix_spawnattr_setcgroup_np, int,
+                 posix_spawnattr_t *, attr,
+                 int, cgroup)
index b283005f40b55670ba5505f1c07a386dd4ce8d51..ffc00f13c647dda71130809b3a4c73ca04b15493 100644 (file)
@@ -1,11 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <sys/stat.h>
-#include <sys/syscall.h>
-#include <unistd.h>
 
-#if !HAVE_FCHMODAT2
-int missing_fchmodat2(int dirfd, const char *path, mode_t mode, int flags) {
-        return syscall(__NR_fchmodat2, dirfd, path, mode, flags);
-}
-#endif
+#include "libc-shim.h"
+
+DEFINE_SYSCALL_SHIM(fchmodat2, int,
+                    int, dirfd,
+                    const char *, path,
+                    mode_t, mode,
+                    int, flags)
index 81728631c6b43260b2eda87a410c4d5b747a6502..22fb704907e1349ce3dd23c9d217b9dadc45de50 100644 (file)
@@ -1,10 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-#include <sys/syscall.h>
-#include <unistd.h>
+#include "libc-shim.h"
 
-#if !HAVE_PIVOT_ROOT
-int missing_pivot_root(const char *new_root, const char *put_old) {
-        return syscall(__NR_pivot_root, new_root, put_old);
-}
-#endif
+DEFINE_SYSCALL_SHIM(pivot_root, int,
+                    const char *, new_root,
+                    const char *, put_old)
index 68fa97ab281d098f236d0c89deea2a67b5abad44..668faa766c9da76b002b74afbc4a4ae6b42645c8 100644 (file)
@@ -1,17 +1,19 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-#include <sys/syscall.h>
 #include <sys/xattr.h>
-#include <unistd.h>
 
-#if !HAVE_SETXATTRAT
-int missing_setxattrat(int fd, const char *path, int at_flags, const char *name, const struct xattr_args *args, size_t size) {
-        return syscall(__NR_setxattrat, fd, path, at_flags, name, args, size);
-}
-#endif
+#include "libc-shim.h"
 
-#if !HAVE_REMOVEXATTRAT
-int missing_removexattrat(int fd, const char *path, int at_flags, const char *name) {
-        return syscall(__NR_removexattrat, fd, path, at_flags, name);
-}
-#endif
+DEFINE_SYSCALL_SHIM(setxattrat, int,
+                    int, fd,
+                    const char *, path,
+                    int, at_flags,
+                    const char *, name,
+                    const struct xattr_args *, args,
+                    size_t, size)
+
+DEFINE_SYSCALL_SHIM(removexattrat, int,
+                    int, fd,
+                    const char *, path,
+                    int, at_flags,
+                    const char *, name)
index 9e7ba7813cde9290de8ba41a176e7b8302ae62bc..8c419fad306ea04736339fc006cb399cf240ef23 100644 (file)
@@ -4629,19 +4629,9 @@ static int epoll_wait_usec(
                 int maxevents,
                 usec_t timeout) {
 
-        int msec;
-        /* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not. */
-
-#if HAVE_EPOLL_PWAIT2
         static bool epoll_pwait2_absent = false;
-        int r;
-
-        /* epoll_pwait2() was added to Linux 5.11 (2021-02-14) and to glibc in 2.35 (2022-02-03). In contrast
-         * to other syscalls we don't bother with our own fallback syscall wrappers on old libcs, since this
-         * is not that obvious to implement given the libc and kernel definitions differ in the last
-         * argument. Moreover, the only reason to use it is the more accurate timeouts (which is not a
-         * biggie), let's hence rely on glibc's definitions, and fallback to epoll_pwait() when that's
-         * missing. */
+        int r, msec;
+        /* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not. */
 
         if (!epoll_pwait2_absent && timeout != USEC_INFINITY) {
                 r = epoll_pwait2(fd,
@@ -4657,7 +4647,6 @@ static int epoll_wait_usec(
 
                 epoll_pwait2_absent = true;
         }
-#endif
 
         if (timeout == USEC_INFINITY)
                 msec = -1;
index 47a148459d95f8338bc05c7ac4919bba3da1d7cd..7aa3d5d9c523123447564cd29c157ce55cbff23a 100644 (file)
@@ -55,9 +55,15 @@ DLSYM_PROTOTYPE(crypt_resume_by_volume_key) = NULL;
 DLSYM_PROTOTYPE(crypt_set_data_device) = NULL;
 DLSYM_PROTOTYPE(crypt_set_data_offset) = NULL;
 DLSYM_PROTOTYPE(crypt_set_debug_level) = NULL;
-#if HAVE_CRYPT_SET_KEYRING_TO_LINK
-DLSYM_PROTOTYPE(crypt_set_keyring_to_link) = NULL;
-#endif
+static int missing_crypt_set_keyring_to_link(
+                struct crypt_device *cd,
+                const char *key_description,
+                const char *old_key_description,
+                const char *key_type_desc,
+                const char *keyring_to_link_vk) {
+        return -ENOSYS;
+}
+DLSYM_PROTOTYPE(crypt_set_keyring_to_link) = missing_crypt_set_keyring_to_link;
 DLSYM_PROTOTYPE(crypt_set_log_callback) = NULL;
 DLSYM_PROTOTYPE(crypt_set_metadata_size) = NULL;
 DLSYM_PROTOTYPE(crypt_set_pbkdf_type) = NULL;
@@ -67,9 +73,10 @@ DLSYM_PROTOTYPE(crypt_token_external_path) = NULL;
 DLSYM_PROTOTYPE(crypt_token_json_get) = NULL;
 DLSYM_PROTOTYPE(crypt_token_json_set) = NULL;
 DLSYM_PROTOTYPE(crypt_token_max) = NULL;
-#if HAVE_CRYPT_TOKEN_SET_EXTERNAL_PATH
-DLSYM_PROTOTYPE(crypt_token_set_external_path) = NULL;
-#endif
+static int missing_crypt_token_set_external_path(const char *path) {
+        return -ENOSYS;
+}
+DLSYM_PROTOTYPE(crypt_token_set_external_path) = missing_crypt_token_set_external_path;
 DLSYM_PROTOTYPE(crypt_token_status) = NULL;
 DLSYM_PROTOTYPE(crypt_volume_key_get) = NULL;
 DLSYM_PROTOTYPE(crypt_volume_key_keyring) = NULL;
@@ -318,9 +325,6 @@ int dlopen_cryptsetup(int log_level) {
                         DLSYM_ARG(crypt_set_data_device),
                         DLSYM_ARG(crypt_set_data_offset),
                         DLSYM_ARG(crypt_set_debug_level),
-#if HAVE_CRYPT_SET_KEYRING_TO_LINK
-                        DLSYM_ARG(crypt_set_keyring_to_link),
-#endif
                         DLSYM_ARG(crypt_set_log_callback),
                         DLSYM_ARG(crypt_set_metadata_size),
                         DLSYM_ARG(crypt_set_pbkdf_type),
@@ -330,9 +334,6 @@ int dlopen_cryptsetup(int log_level) {
                         DLSYM_ARG(crypt_token_json_get),
                         DLSYM_ARG(crypt_token_json_set),
                         DLSYM_ARG(crypt_token_max),
-#if HAVE_CRYPT_TOKEN_SET_EXTERNAL_PATH
-                        DLSYM_ARG(crypt_token_set_external_path),
-#endif
                         DLSYM_ARG(crypt_token_status),
                         DLSYM_ARG(crypt_volume_key_get),
                         DLSYM_ARG(crypt_volume_key_keyring),
@@ -341,6 +342,12 @@ int dlopen_cryptsetup(int log_level) {
         if (r <= 0)
                 return r;
 
+        /* Optional symbols: present in libcryptsetup 2.7+ only. If unresolved, the prototype keeps its
+         * static initializer pointing at a fallback that returns -ENOSYS, so call sites can invoke the
+         * symbol unconditionally. */
+        DLSYM_OPTIONAL(cryptsetup_dl, crypt_set_keyring_to_link);
+        DLSYM_OPTIONAL(cryptsetup_dl, crypt_token_set_external_path);
+
         /* Redirect the default logging calls of libcryptsetup to our own logging infra. (Note that
          * libcryptsetup also maintains per-"struct crypt_device" log functions, which we'll also set
          * whenever allocating a "struct crypt_device" context. Why set both? To be defensive: maybe some
@@ -350,13 +357,11 @@ int dlopen_cryptsetup(int log_level) {
 
         const char *e = secure_getenv("SYSTEMD_CRYPTSETUP_TOKEN_PATH");
         if (e) {
-#if HAVE_CRYPT_TOKEN_SET_EXTERNAL_PATH
                 r = sym_crypt_token_set_external_path(e);
-                if (r < 0)
+                if (r == -ENOSYS)
+                        log_debug("Loaded libcryptsetup does not support setting the external token path, not setting it to '%s'.", e);
+                else if (r < 0)
                         log_debug_errno(r, "Failed to set the libcryptsetup external token path to '%s', ignoring: %m", e);
-#else
-                log_debug("libcryptsetup version does not support setting the external token path, not setting it to '%s'.", e);
-#endif
         }
 
         return 1;
index 4e994ce9f99511d9d2ad727c1b9d4f7fcd9961c4..5c83aad8ee211febd7f9fad6e498da6bc7f2b2dc 100644 (file)
@@ -7,6 +7,19 @@
 #if HAVE_LIBCRYPTSETUP
 #include <libcryptsetup.h> /* IWYU pragma: export */
 
+/* Available since libcryptsetup 2.7. Always redeclare so DLSYM_PROTOTYPE's typeof() resolves on older
+ * headers; suppress the warning when newer libcryptsetup already declares them. */
+DISABLE_WARNING_REDUNDANT_DECLS;
+/* NOLINTBEGIN(readability-redundant-declaration) */
+extern int crypt_set_keyring_to_link(struct crypt_device *cd,
+                                     const char *key_description,
+                                     const char *old_key_description,
+                                     const char *key_type_desc,
+                                     const char *keyring_to_link_vk);
+extern int crypt_token_set_external_path(const char *path);
+/* NOLINTEND(readability-redundant-declaration) */
+REENABLE_WARNING;
+
 extern DLSYM_PROTOTYPE(crypt_activate_by_passphrase);
 extern DLSYM_PROTOTYPE(crypt_activate_by_signed_key);
 extern DLSYM_PROTOTYPE(crypt_activate_by_token_pin);
@@ -43,9 +56,7 @@ extern DLSYM_PROTOTYPE(crypt_resume_by_volume_key);
 extern DLSYM_PROTOTYPE(crypt_set_data_device);
 extern DLSYM_PROTOTYPE(crypt_set_data_offset);
 extern DLSYM_PROTOTYPE(crypt_set_debug_level);
-#if HAVE_CRYPT_SET_KEYRING_TO_LINK
 extern DLSYM_PROTOTYPE(crypt_set_keyring_to_link);
-#endif
 extern DLSYM_PROTOTYPE(crypt_set_log_callback);
 extern DLSYM_PROTOTYPE(crypt_set_metadata_size);
 extern DLSYM_PROTOTYPE(crypt_set_pbkdf_type);
@@ -55,9 +66,7 @@ extern DLSYM_PROTOTYPE(crypt_token_external_path);
 extern DLSYM_PROTOTYPE(crypt_token_json_get);
 extern DLSYM_PROTOTYPE(crypt_token_json_set);
 extern DLSYM_PROTOTYPE(crypt_token_max);
-#if HAVE_CRYPT_TOKEN_SET_EXTERNAL_PATH
 extern DLSYM_PROTOTYPE(crypt_token_set_external_path);
-#endif
 extern DLSYM_PROTOTYPE(crypt_token_status);
 extern DLSYM_PROTOTYPE(crypt_volume_key_get);
 extern DLSYM_PROTOTYPE(crypt_volume_key_keyring);
index 7c3d10f9e33748611fd003051ec98f11e0ea50c1..02035404a65debd0fb80e42cb55593a62d6ed530 100644 (file)
@@ -56,9 +56,12 @@ static DLSYM_PROTOTYPE(dwfl_begin) = NULL;
 static DLSYM_PROTOTYPE(dwfl_build_id_find_elf) = NULL;
 static DLSYM_PROTOTYPE(dwfl_core_file_attach) = NULL;
 static DLSYM_PROTOTYPE(dwfl_core_file_report) = NULL;
-#if HAVE_DWFL_SET_SYSROOT
+/* New in elfutils 0.192. Always redeclare so DLSYM_PROTOTYPE's typeof() resolves on older headers; suppress
+ * the warning when newer libdw already declared it. */
+DISABLE_WARNING_REDUNDANT_DECLS;
+extern int dwfl_set_sysroot(Dwfl *dwfl, const char *sysroot); /* NOLINT(readability-redundant-declaration) */
+REENABLE_WARNING;
 static DLSYM_PROTOTYPE(dwfl_set_sysroot) = NULL;
-#endif
 static DLSYM_PROTOTYPE(dwfl_end) = NULL;
 static DLSYM_PROTOTYPE(dwfl_errmsg) = NULL;
 static DLSYM_PROTOTYPE(dwfl_errno) = NULL;
@@ -121,9 +124,6 @@ int dlopen_dw(int log_level) {
                         DLSYM_ARG(dwfl_module_getelf),
                         DLSYM_ARG(dwfl_begin),
                         DLSYM_ARG(dwfl_core_file_report),
-#if HAVE_DWFL_SET_SYSROOT
-                        DLSYM_ARG(dwfl_set_sysroot),
-#endif
                         DLSYM_ARG(dwfl_report_end),
                         DLSYM_ARG(dwfl_getmodules),
                         DLSYM_ARG(dwfl_core_file_attach),
@@ -139,6 +139,9 @@ int dlopen_dw(int log_level) {
         if (r <= 0)
                 return r;
 
+        /* Optional symbol: present in libdw 0.192+. NULL pointer is fine; call sites check at use. */
+        DLSYM_OPTIONAL(dw_dl, dwfl_set_sysroot);
+
         return 1;
 #else
         return log_full_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
@@ -146,6 +149,16 @@ int dlopen_dw(int log_level) {
 #endif
 }
 
+bool dlopen_dw_has_dwfl_set_sysroot(void) {
+#if HAVE_ELFUTILS
+        if (dlopen_dw(LOG_DEBUG) < 0)
+                return false;
+        return sym_dwfl_set_sysroot;
+#else
+        return false;
+#endif
+}
+
 int dlopen_elf(int log_level) {
 #if HAVE_ELFUTILS
         int r;
@@ -660,13 +673,13 @@ static int parse_core(
 
         if (empty_or_root(root))
                 root = NULL;
-#if HAVE_DWFL_SET_SYSROOT
-        if (root && sym_dwfl_set_sysroot(c.dwfl, root) < 0)
-                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not set root directory, dwfl_set_sysroot() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
-#else
-        if (root)
-                log_warning("Compiled without dwfl_set_sysroot() support, ignoring provided root directory.");
-#endif
+        if (root) {
+                if (sym_dwfl_set_sysroot) {
+                        if (sym_dwfl_set_sysroot(c.dwfl, root) < 0)
+                                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not set root directory, dwfl_set_sysroot() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
+                } else
+                        log_warning("Loaded libdw does not support dwfl_set_sysroot(), ignoring provided root directory.");
+        }
 
         if (sym_dwfl_core_file_report(c.dwfl, c.elf, executable) < 0)
                 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Could not parse core file, dwfl_core_file_report() failed: %s", sym_dwfl_errmsg(sym_dwfl_errno()));
index e9d9e959dab3d499f6593080f993264cbaceb220..7ccbec56c6461536780aa2952ba778a371a35a83 100644 (file)
@@ -6,6 +6,8 @@
 int dlopen_dw(int log_level);
 int dlopen_elf(int log_level);
 
+bool dlopen_dw_has_dwfl_set_sysroot(void);
+
 /* Parse an ELF object in a forked process, so that errors while iterating over
  * untrusted and potentially malicious data do not propagate to the main caller's process.
  * If fork_disable_dump, the child process will not dump core if it crashes. */
index 2ef0b37959b934b8b21217e64a8955e2c98304ce..f0f3439f9284d3683478e62ad024aaf44bbbde0e 100644 (file)
@@ -18,17 +18,15 @@ DLSYM_PROTOTYPE(archive_entry_fflags) = NULL;
 DLSYM_PROTOTYPE(archive_entry_filetype) = NULL;
 DLSYM_PROTOTYPE(archive_entry_free) = NULL;
 DLSYM_PROTOTYPE(archive_entry_gid) = NULL;
-#if HAVE_ARCHIVE_ENTRY_GID_IS_SET
-DLSYM_PROTOTYPE(archive_entry_gid_is_set) = NULL;
-#else
-int sym_archive_entry_gid_is_set(struct archive_entry *e) {
+static int missing_archive_entry_gid_is_set(struct archive_entry *e) {
         return gid_is_valid(sym_archive_entry_gid(e));
 }
-#endif
+DLSYM_PROTOTYPE(archive_entry_gid_is_set) = missing_archive_entry_gid_is_set;
 DLSYM_PROTOTYPE(archive_entry_hardlink) = NULL;
-#if HAVE_ARCHIVE_ENTRY_HARDLINK_IS_SET
-DLSYM_PROTOTYPE(archive_entry_hardlink_is_set) = NULL;
-#endif
+static int missing_archive_entry_hardlink_is_set(struct archive_entry *e) {
+        return !!sym_archive_entry_hardlink(e);
+}
+DLSYM_PROTOTYPE(archive_entry_hardlink_is_set) = missing_archive_entry_hardlink_is_set;
 DLSYM_PROTOTYPE(archive_entry_mode) = NULL;
 DLSYM_PROTOTYPE(archive_entry_mtime) = NULL;
 DLSYM_PROTOTYPE(archive_entry_mtime_is_set) = NULL;
@@ -53,13 +51,10 @@ DLSYM_PROTOTYPE(archive_entry_set_uid) = NULL;
 DLSYM_PROTOTYPE(archive_entry_sparse_add_entry) = NULL;
 DLSYM_PROTOTYPE(archive_entry_symlink) = NULL;
 DLSYM_PROTOTYPE(archive_entry_uid) = NULL;
-#if HAVE_ARCHIVE_ENTRY_UID_IS_SET
-DLSYM_PROTOTYPE(archive_entry_uid_is_set) = NULL;
-#else
-int sym_archive_entry_uid_is_set(struct archive_entry *e) {
+static int missing_archive_entry_uid_is_set(struct archive_entry *e) {
         return uid_is_valid(sym_archive_entry_uid(e));
 }
-#endif
+DLSYM_PROTOTYPE(archive_entry_uid_is_set) = missing_archive_entry_uid_is_set;
 DLSYM_PROTOTYPE(archive_entry_xattr_add_entry) = NULL;
 DLSYM_PROTOTYPE(archive_entry_xattr_next) = NULL;
 DLSYM_PROTOTYPE(archive_entry_xattr_reset) = NULL;
@@ -84,13 +79,15 @@ DLSYM_PROTOTYPE(archive_write_set_format_pax) = NULL;
 
 int dlopen_libarchive(int log_level) {
 #if HAVE_LIBARCHIVE
+        int r;
+
         SD_ELF_NOTE_DLOPEN(
                         "archive",
                         "Support for decompressing archive files",
                         SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
                         "libarchive.so.13");
 
-        return dlopen_many_sym_or_warn(
+        r = dlopen_many_sym_or_warn(
                         &libarchive_dl,
                         "libarchive.so.13",
                         log_level,
@@ -101,13 +98,7 @@ int dlopen_libarchive(int log_level) {
                         DLSYM_ARG(archive_entry_filetype),
                         DLSYM_ARG(archive_entry_free),
                         DLSYM_ARG(archive_entry_gid),
-#if HAVE_ARCHIVE_ENTRY_GID_IS_SET
-                        DLSYM_ARG(archive_entry_gid_is_set),
-#endif
                         DLSYM_ARG(archive_entry_hardlink),
-#if HAVE_ARCHIVE_ENTRY_HARDLINK_IS_SET
-                        DLSYM_ARG(archive_entry_hardlink_is_set),
-#endif
                         DLSYM_ARG(archive_entry_mode),
                         DLSYM_ARG(archive_entry_mtime),
                         DLSYM_ARG(archive_entry_mtime_is_set),
@@ -132,9 +123,6 @@ int dlopen_libarchive(int log_level) {
                         DLSYM_ARG(archive_entry_sparse_add_entry),
                         DLSYM_ARG(archive_entry_symlink),
                         DLSYM_ARG(archive_entry_uid),
-#if HAVE_ARCHIVE_ENTRY_UID_IS_SET
-                        DLSYM_ARG(archive_entry_uid_is_set),
-#endif
                         DLSYM_ARG(archive_entry_xattr_add_entry),
                         DLSYM_ARG(archive_entry_xattr_next),
                         DLSYM_ARG(archive_entry_xattr_reset),
@@ -155,6 +143,16 @@ int dlopen_libarchive(int log_level) {
                         DLSYM_ARG(archive_write_open_fd),
                         DLSYM_ARG(archive_write_set_format_filter_by_ext),
                         DLSYM_ARG(archive_write_set_format_pax));
+        if (r <= 0)
+                return r;
+
+        /* Optional symbols: present in newer libarchive versions only. If missing, sym_X keeps its
+         * fallback-function initializer (see above). */
+        DLSYM_OPTIONAL(libarchive_dl, archive_entry_gid_is_set);
+        DLSYM_OPTIONAL(libarchive_dl, archive_entry_uid_is_set);
+        DLSYM_OPTIONAL(libarchive_dl, archive_entry_hardlink_is_set);
+
+        return 1;
 #else
         return log_full_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP),
                               "libarchive support is not compiled in.");
index f1f78aad5d1eb87147d3d5b77add46448713c102..9f47ea67eacd0d23dc2973bd09981cd647a7dbfd 100644 (file)
@@ -9,6 +9,16 @@
 
 #include "dlfcn-util.h"
 
+/* Newer symbols that might not be in the header we build against. Always redeclare so DLSYM_PROTOTYPE's
+ * typeof() resolves; suppress the warning when newer libarchive already declared them. */
+DISABLE_WARNING_REDUNDANT_DECLS;
+/* NOLINTBEGIN(readability-redundant-declaration) */
+extern int archive_entry_gid_is_set(struct archive_entry *e);
+extern int archive_entry_hardlink_is_set(struct archive_entry *e);
+extern int archive_entry_uid_is_set(struct archive_entry *e);
+/* NOLINTEND(readability-redundant-declaration) */
+REENABLE_WARNING;
+
 extern DLSYM_PROTOTYPE(archive_entry_acl_add_entry);
 extern DLSYM_PROTOTYPE(archive_entry_acl_next);
 extern DLSYM_PROTOTYPE(archive_entry_acl_reset);
@@ -16,19 +26,9 @@ extern DLSYM_PROTOTYPE(archive_entry_fflags);
 extern DLSYM_PROTOTYPE(archive_entry_filetype);
 extern DLSYM_PROTOTYPE(archive_entry_free);
 extern DLSYM_PROTOTYPE(archive_entry_gid);
-#if HAVE_ARCHIVE_ENTRY_GID_IS_SET
 extern DLSYM_PROTOTYPE(archive_entry_gid_is_set);
-#else
-int sym_archive_entry_gid_is_set(struct archive_entry *e);
-#endif
 extern DLSYM_PROTOTYPE(archive_entry_hardlink);
-#if HAVE_ARCHIVE_ENTRY_HARDLINK_IS_SET
 extern DLSYM_PROTOTYPE(archive_entry_hardlink_is_set);
-#else
-static inline int sym_archive_entry_hardlink_is_set(struct archive_entry *e) {
-        return !!sym_archive_entry_hardlink(e);
-}
-#endif
 extern DLSYM_PROTOTYPE(archive_entry_mode);
 extern DLSYM_PROTOTYPE(archive_entry_mtime);
 extern DLSYM_PROTOTYPE(archive_entry_mtime_is_set);
@@ -53,11 +53,7 @@ extern DLSYM_PROTOTYPE(archive_entry_set_uid);
 extern DLSYM_PROTOTYPE(archive_entry_sparse_add_entry);
 extern DLSYM_PROTOTYPE(archive_entry_symlink);
 extern DLSYM_PROTOTYPE(archive_entry_uid);
-#if HAVE_ARCHIVE_ENTRY_UID_IS_SET
 extern DLSYM_PROTOTYPE(archive_entry_uid_is_set);
-#else
-int sym_archive_entry_uid_is_set(struct archive_entry *e);
-#endif
 extern DLSYM_PROTOTYPE(archive_entry_xattr_add_entry);
 extern DLSYM_PROTOTYPE(archive_entry_xattr_next);
 extern DLSYM_PROTOTYPE(archive_entry_xattr_reset);