:p
atchew
Login
This commit adds support for the `openat2()` syscall in the `linux-user` userspace emulator. It is implemented by extracting a new helper `maybe_do_fake_open()` out of the exiting `do_guest_openat()` and share that with the new `do_guest_openat2()`. Unfortunatly we cannot just make do_guest_openat2() a superset of do_guest_openat() because the openat2() syscall is stricter with the argument checking and will return an error for invalid flags or mode combinations (which open()/openat() will ignore). Note that in this commit using openat2() for a "faked" file in /proc will ignore the "resolve" flags. This is not great but it seems similar to the exiting behavior when openat() is called with a dirfd to "/proc". Here too the fake file lookup may not catch the special file because "realpath()" is used to determine if the path is in /proc. Alternatively to ignoring we could simply fail with `-TARGET_ENOSYS` (or similar) if `resolve` flags are passed and we found something that looks like a file in /proc that needs faking. Signed-off-by: Michael Vogt <mvogt@redhat.com> Buglink: https://github.com/osbuild/bootc-image-builder/issues/619 --- linux-user/qemu.h | 4 +++ linux-user/syscall.c | 73 ++++++++++++++++++++++++++++++++++++--- linux-user/syscall_defs.h | 7 ++++ meson.build | 1 + 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -XXX,XX +XXX,XX @@ struct TaskState { abi_long do_brk(abi_ulong new_brk); int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, int flags, mode_t mode, bool safe); +#ifdef HAVE_OPENAT2_H +int do_guest_openat2(CPUArchState *cpu_env, int dirfd, const char *pathname, + struct target_open_how *how, bool safe); +#endif ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz); /* user access */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -XXX,XX +XXX,XX @@ #include <sys/kcov.h> #endif +#ifdef HAVE_OPENAT2_H +#include <linux/openat2.h> +/* glibc has no header for SYS_openat2 so we need to get it via syscall.h */ +#include <sys/syscall.h> +#endif + #define termios host_termios #define winsize host_winsize #define termio host_termio @@ -XXX,XX +XXX,XX @@ safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count) safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count) safe_syscall4(int, openat, int, dirfd, const char *, pathname, \ int, flags, mode_t, mode) +#ifdef HAVE_OPENAT2_H +safe_syscall4(int, openat2, int, dirfd, const char *, pathname, \ + const struct open_how *, how, size_t, size); +#endif #if defined(TARGET_NR_wait4) || defined(TARGET_NR_waitpid) safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \ struct rusage *, rusage) @@ -XXX,XX +XXX,XX @@ static int open_net_route(CPUArchState *cpu_env, int fd) } #endif -int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, - int flags, mode_t mode, bool safe) +static int maybe_do_fake_open(CPUArchState *cpu_env, int dirfd, + const char *fname, int flags, mode_t mode, + bool safe) { g_autofree char *proc_name = NULL; const char *pathname; @@ -XXX,XX +XXX,XX @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, return fd; } + return -1; +} + +int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, + int flags, mode_t mode, bool safe) +{ + int fd = maybe_do_fake_open(cpu_env, dirfd, fname, flags, mode, safe); + if (fd >= 0) + return fd; + if (safe) { - return safe_openat(dirfd, path(pathname), flags, mode); + return safe_openat(dirfd, path(fname), flags, mode); } else { - return openat(dirfd, path(pathname), flags, mode); + return openat(dirfd, path(fname), flags, mode); } } +#ifdef HAVE_OPENAT2_H +int do_guest_openat2(CPUArchState *cpu_env, int dirfd, const char *fname, + struct target_open_how *how, bool safe) +{ + /* + * Ideally we would pass "how->resolve" flags into this helper too but + * the lookup for files that need faking is based on "realpath()" so + * neither a dirfd for "proc" nor restrictions via "resolve" flags can + * be honored right now. + */ + int fd = maybe_do_fake_open(cpu_env, dirfd, fname, how->flags, how->mode, + safe); + if (fd >= 0) + return fd; + + if (safe) { + return safe_openat2(dirfd, fname, (struct open_how *)how, + sizeof(struct target_open_how)); + } else { + return syscall(SYS_openat2, dirfd, fname, (struct open_hosw *)how, + sizeof(struct target_open_how)); + } +} +#endif + ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz) { ssize_t ret; @@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, fd_trans_unregister(ret); unlock_user(p, arg2, 0); return ret; +#if defined(TARGET_NR_openat2) && defined(HAVE_OPENAT2_H) + case TARGET_NR_openat2: + { + struct target_open_how how, *target_how; + if (!(p = lock_user_string(arg2))) + return -TARGET_EFAULT; + if (!(lock_user_struct(VERIFY_READ, target_how, arg3, 1))) + return -TARGET_EFAULT; + how.flags = target_to_host_bitmask(target_how->flags, + fcntl_flags_tbl); + how.mode = tswap64(target_how->mode); + how.resolve = tswap64(target_how->resolve); + ret = get_errno(do_guest_openat2(cpu_env, arg1, p, &how, true)); + fd_trans_unregister(ret); + unlock_user_struct(target_how, arg3, 0); + unlock_user(p, arg2, 0); + return ret; + } +#endif #if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) case TARGET_NR_name_to_handle_at: ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -XXX,XX +XXX,XX @@ struct target_sched_param { abi_int sched_priority; }; +/* from kernel's include/uapi/linux/openat2.h */ +struct target_open_how { + __u64 flags; + __u64 mode; + __u64 resolve; +}; + #endif diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h')) config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h')) config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h')) config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h')) +config_host_data.set('HAVE_OPENAT2_H', cc.has_header('linux/openat2.h')) config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h')) config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h')) config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h')) -- 2.45.2
This is v9 of the openat2 support in linux-user. Thanks to Laurent for spotting another missing tswap64() in v8 (and my appologies that I overlooked this). Looking forward to your feedback/ideas! Thanks, Michael v8 -> v9 - use "tswap64()" in strace.c for how.{flags,mode,resolve} v7 -> v8 - use "tswap64(how.flags)" in do_openat2() - drop printing "size=" from strace.c v6 -> v7 - use abi_ulong in guest_size - use TARGET_ABI_FMT_lu to format guest size in qemu_log_mask() - drop #ifdef for TARGET_NR_openat2 - fix LTP test by checking for RESOLVE_NO_{MAGIC,SYM}LINKS in maybe_do_fake_open() - add support for openat2 in strace.c - add copy_struct_from_user definition to qemu.h - add open_how_v0 to syscall_defs.h v5 -> v6 - do not use get_errno(fd) in do_guest_openat() - do not put declarations in the middle of the code - do not return early in do_openat2() when we get a faked file v4 -> v5 - drop "*use_returned_fd" from maybe_do_fake_open() and use return value -2 to signal to the caller to continue - keep "pathname" in parameter to do_guest_openat() for a cleaner diff - fix two missing get_errno(fd) v3 -> v4: - fix typos in the commit message v2 -> v3: - fix coding style (braches) - improve argument args/naming in do_openat2() - merge do_openat2/do_guest_openat2 - do size checks first in do_openat2 - add "copy_struct_from_user" and use in "do_openat2()" - drop using openat2.h and create "struct open_how_v0" - log if open_how guest struct is bigger than our supported struct v1 -> v2: - do not include <sys/syscall.h> - drop do_guest_openat2 from qemu.h and make static - drop "safe" from do_guest_openat2 - ensure maybe_do_fake_open() is correct about when the result should be used or not - Extract do_openat2() helper from do_syscall1() - Call user_unlock* if a lock call fails - Fix silly incorrect use of "target_open_how" when "open_how" is required - Fix coding style comments - Fix validation of arg4 in openat2 - Fix missing zero initialization of open_how - Define target_open_how with abi_* types - Warn about unimplemented size if "size" of openat2 is bigger than target_open_how Michael Vogt (2): linux-user: add openat2 support in linux-user linux-user: add strace support for openat2 linux-user/qemu.h | 9 ++++ linux-user/strace.c | 44 +++++++++++++++++ linux-user/strace.list | 3 ++ linux-user/syscall.c | 99 ++++++++++++++++++++++++++++++++++++++- linux-user/syscall_defs.h | 18 +++++++ meson.build | 1 + 6 files changed, 172 insertions(+), 2 deletions(-) -- 2.45.2
This commit adds support for the `openat2()` syscall in the `linux-user` userspace emulator. It is implemented by extracting a new helper `maybe_do_fake_open()` out of the exiting `do_guest_openat()` and share that with the new `do_guest_openat2()`. Unfortunately we cannot just make do_guest_openat2() a superset of do_guest_openat() because the openat2() syscall is stricter with the argument checking and will return an error for invalid flags or mode combinations (which open()/openat() will ignore). The implementation is similar to SYSCALL_DEFINE(openat2), i.e. a new `copy_struct_from_user()` is used that works the same as the kernels version to support backwards-compatibility for struct syscall argument. Instead of including openat2.h we create a copy of `open_how` as `open_how_ver0` to ensure that if the structure grows we can log a LOG_UNIMP warning. Note that in this commit using openat2() for a "faked" file in /proc will honor the "resolve" flags for RESOLVE_NO_{MAGIC,SYM}LINKS for path based access to /proc/self/exe (which is the only magic link we support for faked files). Note it will not catch special access via e.g. dirfd. This is not great but it seems similar to the exiting behavior when openat() is called with a dirfd to "/proc". Here too the fake file lookup may not catch the special file because no dirfd is used to determine if the path is in /proc. Signed-off-by: Michael Vogt <mvogt@redhat.com> Buglink: https://github.com/osbuild/bootc-image-builder/issues/619 --- linux-user/syscall.c | 105 +++++++++++++++++++++++++++++++++++++- linux-user/syscall_defs.h | 13 +++++ 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -XXX,XX +XXX,XX @@ static int check_zeroed_user(abi_long addr, size_t ksize, size_t usize) return 1; } +/* + * Copies a target struct to a host struct, in a way that guarantees + * backwards-compatibility for struct syscall arguments. + * + * Similar to kernels uaccess.h:copy_struct_from_user() + */ +static int +copy_struct_from_user(void *dst, size_t ksize, abi_ptr src, size_t usize) +{ + size_t size = MIN(ksize, usize); + size_t rest = MAX(ksize, usize) - size; + + /* Deal with trailing bytes. */ + if (usize < ksize) { + memset(dst + size, 0, rest); + } else if (usize > ksize) { + int ret = check_zeroed_user(src, ksize, usize); + if (ret <= 0) { + return ret ?: -TARGET_E2BIG; + } + } + /* Copy the interoperable parts of the struct. */ + if (copy_from_user(dst, src, size)) { + return -TARGET_EFAULT; + } + return 0; +} + #define safe_syscall0(type, name) \ static type safe_##name(void) \ { \ @@ -XXX,XX +XXX,XX @@ safe_syscall3(ssize_t, read, int, fd, void *, buff, size_t, count) safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count) safe_syscall4(int, openat, int, dirfd, const char *, pathname, \ int, flags, mode_t, mode) + +struct open_how_ver0 { + __u64 flags; + __u64 mode; + __u64 resolve; +}; +safe_syscall4(int, openat2, int, dirfd, const char *, pathname, \ + const struct open_how_ver0 *, how, size_t, size) + #if defined(TARGET_NR_wait4) || defined(TARGET_NR_waitpid) safe_syscall4(pid_t, wait4, pid_t, pid, int *, status, int, options, \ struct rusage *, rusage) @@ -XXX,XX +XXX,XX @@ static int open_net_route(CPUArchState *cpu_env, int fd) } #endif -int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, - int flags, mode_t mode, bool safe) +static int maybe_do_fake_open(CPUArchState *cpu_env, int dirfd, + const char *fname, int flags, mode_t mode, + int openat2_resolve, bool safe) { g_autofree char *proc_name = NULL; const char *pathname; @@ -XXX,XX +XXX,XX @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, } if (is_proc_myself(pathname, "exe")) { + /* Honor openat2 resolve flags */ + if ((openat2_resolve & RESOLVE_NO_MAGICLINKS) || + (openat2_resolve & RESOLVE_NO_SYMLINKS)) { + errno = ELOOP; + return -1; + } if (safe) { return safe_openat(dirfd, exec_path, flags, mode); } else { @@ -XXX,XX +XXX,XX @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, return fd; } + return -2; +} + +int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *pathname, + int flags, mode_t mode, bool safe) +{ + int fd = maybe_do_fake_open(cpu_env, dirfd, pathname, flags, mode, 0, safe); + if (fd > -2) { + return fd; + } + if (safe) { return safe_openat(dirfd, path(pathname), flags, mode); } else { @@ -XXX,XX +XXX,XX @@ int do_guest_openat(CPUArchState *cpu_env, int dirfd, const char *fname, } } + +static int do_openat2(CPUArchState *cpu_env, abi_long dirfd, + abi_ptr guest_pathname, abi_ptr guest_open_how, + abi_ulong guest_size) +{ + struct open_how_ver0 how = {0}; + char *pathname; + int ret; + + if (guest_size < sizeof(struct target_open_how_ver0)) { + return -TARGET_EINVAL; + } + ret = copy_struct_from_user(&how, sizeof(how), guest_open_how, guest_size); + if (ret) { + if (ret == -TARGET_E2BIG) { + qemu_log_mask(LOG_UNIMP, + "Unimplemented openat2 open_how size: " + TARGET_ABI_FMT_lu "\n", guest_size); + } + return ret; + } + pathname = lock_user_string(guest_pathname); + if (!pathname) { + return -TARGET_EFAULT; + } + + how.flags = target_to_host_bitmask(tswap64(how.flags), fcntl_flags_tbl); + how.mode = tswap64(how.mode); + how.resolve = tswap64(how.resolve); + int fd = maybe_do_fake_open(cpu_env, dirfd, pathname, how.flags, how.mode, + how.resolve, true); + if (fd > -2) { + ret = get_errno(fd); + } else { + ret = get_errno(safe_openat2(dirfd, pathname, &how, + sizeof(struct open_how_ver0))); + } + + fd_trans_unregister(ret); + unlock_user(pathname, guest_pathname, 0); + return ret; +} + ssize_t do_guest_readlink(const char *pathname, char *buf, size_t bufsiz) { ssize_t ret; @@ -XXX,XX +XXX,XX @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, fd_trans_unregister(ret); unlock_user(p, arg2, 0); return ret; + case TARGET_NR_openat2: + ret = do_openat2(cpu_env, arg1, arg2, arg3, arg4); + return ret; #if defined(TARGET_NR_name_to_handle_at) && defined(CONFIG_OPEN_BY_HANDLE) case TARGET_NR_name_to_handle_at: ret = do_name_to_handle_at(arg1, arg2, arg3, arg4, arg5); diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -XXX,XX +XXX,XX @@ struct target_sched_param { abi_int sched_priority; }; +/* from kernel's include/uapi/linux/openat2.h */ +struct target_open_how_ver0 { + abi_ullong flags; + abi_ullong mode; + abi_ullong resolve; +}; +#ifndef RESOLVE_NO_MAGICLINKS +#define RESOLVE_NO_MAGICLINKS 0x02 +#endif +#ifndef RESOLVE_NO_SYMLINKS +#define RESOLVE_NO_SYMLINKS 0x04 +#endif + #endif -- 2.45.2
This commit adds support for the `openat2()` to `QEMU_STRACE`. It will use the `openat2.h` header if available to create user readable flags for the `resolve` argument but does not require the header otherwise. It also makes `copy_struct_from_user()` available via `qemu.h` and `open_how_ver0` via `syscall_defs.h` so that strace.c can use them. Signed-off-by: Michael Vogt <mvogt@redhat.com> --- linux-user/qemu.h | 9 ++++++++ linux-user/strace.c | 44 +++++++++++++++++++++++++++++++++++++++ linux-user/strace.list | 3 +++ linux-user/syscall.c | 8 +------ linux-user/syscall_defs.h | 5 +++++ meson.build | 1 + 6 files changed, 63 insertions(+), 7 deletions(-) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -XXX,XX +XXX,XX @@ static inline bool access_ok(CPUState *cpu, int type, int copy_from_user(void *hptr, abi_ulong gaddr, ssize_t len); int copy_to_user(abi_ulong gaddr, void *hptr, ssize_t len); +/* + * copy_struct_from_user() copies a target struct to a host struct, in + * a way that guarantees backwards-compatibility for struct syscall + * arguments. + * + * Similar to kernels uaccess.h:copy_struct_from_user() + */ +int copy_struct_from_user(void *dst, size_t ksize, abi_ptr src, size_t usize); + /* Functions for accessing guest memory. The tget and tput functions read/write single values, byteswapping as necessary. The lock_user function gets a pointer to a contiguous area of guest memory, but does not perform diff --git a/linux-user/strace.c b/linux-user/strace.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -XXX,XX +XXX,XX @@ #include <linux/if_packet.h> #include <linux/in6.h> #include <linux/netlink.h> +#ifdef HAVE_OPENAT2_H +#include <linux/openat2.h> +#endif #include <sched.h> #include "qemu.h" #include "user-internals.h" @@ -XXX,XX +XXX,XX @@ UNUSED static const struct flags open_flags[] = { FLAG_END, }; +UNUSED static const struct flags openat2_resolve_flags[] = { +#ifdef HAVE_OPENAT2_H + FLAG_GENERIC(RESOLVE_NO_XDEV), + FLAG_GENERIC(RESOLVE_NO_MAGICLINKS), + FLAG_GENERIC(RESOLVE_NO_SYMLINKS), + FLAG_GENERIC(RESOLVE_BENEATH), + FLAG_GENERIC(RESOLVE_IN_ROOT), + FLAG_GENERIC(RESOLVE_CACHED), +#endif + FLAG_END, +}; + UNUSED static const struct flags mount_flags[] = { #ifdef MS_BIND FLAG_GENERIC(MS_BIND), @@ -XXX,XX +XXX,XX @@ print_openat(CPUArchState *cpu_env, const struct syscallname *name, } #endif +#ifdef TARGET_NR_openat2 +static void +print_openat2(CPUArchState *cpu_env, const struct syscallname *name, + abi_long arg0, abi_long arg1, abi_long arg2, + abi_long arg3, abi_long arg4, abi_long arg5) +{ + struct open_how_ver0 how = {0}; + + print_syscall_prologue(name); + print_at_dirfd(arg0, 0); + print_string(arg1, 0); + if (copy_struct_from_user(&how, sizeof(how), arg2, arg3) == 0) { + how.flags = tswap64(how.flags); + how.mode = tswap64(how.mode); + how.resolve = tswap64(how.resolve); + + print_open_flags(how.flags, 0); + if (how.flags & TARGET_O_CREAT) { + print_file_mode(how.mode, 0); + } + print_flags(openat2_resolve_flags, how.resolve, 0); + } else { + print_pointer(arg2, 0); + } + print_raw_param(TARGET_ABI_FMT_lu, arg3, 1); + print_syscall_epilogue(name); +} +#endif + #ifdef TARGET_NR_pidfd_send_signal static void print_pidfd_send_signal(CPUArchState *cpu_env, const struct syscallname *name, diff --git a/linux-user/strace.list b/linux-user/strace.list index XXXXXXX..XXXXXXX 100644 --- a/linux-user/strace.list +++ b/linux-user/strace.list @@ -XXX,XX +XXX,XX @@ #ifdef TARGET_NR_openat { TARGET_NR_openat, "openat" , NULL, print_openat, NULL }, #endif +#ifdef TARGET_NR_openat2 +{ TARGET_NR_openat2, "openat2" , NULL, print_openat2, NULL }, +#endif #ifdef TARGET_NR_osf_adjtime { TARGET_NR_osf_adjtime, "osf_adjtime" , NULL, NULL, NULL }, #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -XXX,XX +XXX,XX @@ static int check_zeroed_user(abi_long addr, size_t ksize, size_t usize) * * Similar to kernels uaccess.h:copy_struct_from_user() */ -static int -copy_struct_from_user(void *dst, size_t ksize, abi_ptr src, size_t usize) +int copy_struct_from_user(void *dst, size_t ksize, abi_ptr src, size_t usize) { size_t size = MIN(ksize, usize); size_t rest = MAX(ksize, usize) - size; @@ -XXX,XX +XXX,XX @@ safe_syscall3(ssize_t, write, int, fd, const void *, buff, size_t, count) safe_syscall4(int, openat, int, dirfd, const char *, pathname, \ int, flags, mode_t, mode) -struct open_how_ver0 { - __u64 flags; - __u64 mode; - __u64 resolve; -}; safe_syscall4(int, openat2, int, dirfd, const char *, pathname, \ const struct open_how_ver0 *, how, size_t, size) diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -XXX,XX +XXX,XX @@ struct target_sched_param { }; /* from kernel's include/uapi/linux/openat2.h */ +struct open_how_ver0 { + __u64 flags; + __u64 mode; + __u64 resolve; +}; struct target_open_how_ver0 { abi_ullong flags; abi_ullong mode; diff --git a/meson.build b/meson.build index XXXXXXX..XXXXXXX 100644 --- a/meson.build +++ b/meson.build @@ -XXX,XX +XXX,XX @@ config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h')) config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h')) config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h')) config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h')) +config_host_data.set('HAVE_OPENAT2_H', cc.has_header('linux/openat2.h')) config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h')) config_host_data.set('HAVE_SYS_DISK_H', cc.has_header('sys/disk.h')) config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h')) -- 2.45.2