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')
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'))
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())
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'))
#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
/* 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;
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)
if (r != 0)
return -r;
-#if HAVE_PIDFD_SPAWN
_cleanup_close_ int pidfd = -EBADF;
r = pidfd_spawn(&pidfd, path, NULL, &attr, argv, envp);
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);
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) {
#include "conf-parser.h"
#include "coredump-config.h"
+#include "elf-util.h"
#include "format-util.h"
#include "journal-def.h"
#include "log.h"
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));
}
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;
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) {
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;
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)
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);
#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. */
/* 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
/* 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. */
#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
--- /dev/null
+/* 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
#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
--- /dev/null
+/* 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
#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
#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
/* 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
#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
#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
/* 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
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
/* 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
#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
#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
#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
#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
/* 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)
--- /dev/null
+/* 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)
/* 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)
/* 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)
/* 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)
/* 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
/* 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)
--- /dev/null
+/* 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; \
+ }
/* 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)
libc_wrapper_sources = files(
'bpf.c',
+ 'epoll.c',
'fcntl.c',
'ioprio.c',
'kcmp.c',
'quota.c',
'sched.c',
'signal.c',
+ 'spawn.c',
'stat.c',
'unistd.c',
'xattr.c',
/* 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)
#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) { \
/* 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)
/* 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)
/* 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)
/* 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)
--- /dev/null
+/* 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)
/* 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)
/* 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)
/* 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)
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,
epoll_pwait2_absent = true;
}
-#endif
if (timeout == USEC_INFINITY)
msec = -1;
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;
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;
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),
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),
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
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;
#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);
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);
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);
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;
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),
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),
#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;
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()));
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. */
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;
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;
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,
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),
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),
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.");
#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);
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);
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);