@@ -31,6 +31,10 @@ Major new features:
* The iconv program now supports converting files in place. The program
automatically uses a temporary file if required.
+* On Linux, the openat2 function has been added. It is an extension of
+ openat and provides a superset of its functionality. It is supported only
+ in LFS mode and it is a cancellable entrypoint.
+
Deprecated and removed features, and other changes affecting compatibility:
* The big-endian ARC port (arceb-linux-gnu) has been removed.
@@ -218,6 +218,103 @@ new, extended API using 64 bit file sizes and offsets transparently
replaces the old API.
@end deftypefun
+@deftp {Data Type} {struct open_how}
+@standards{Linux, fcntl.h}
+The @code{open_how} structure describes how to open a file using @code{openat2}.
+
+@strong{Portability note:} In the future, additional fields can be added
+to @code{struct open_how} at the end, so that the size of this data
+type changes. Do not use it in places where this matters, such as
+structure fields in installed header files, where such a change could
+impact the application binary interface (ABI).
+
+The following generic fields are available.
+
+@table @code
+@item flags
+This field specifies the file creation and file status flags to use when
+opening the file.
+All of the @code{O_*} flags defined for @code{openat} are valid.
+Different than @code{openat}, @code{openat2} returns an error for unknown
+or conflicting values.
+
+@item mode
+This field specifies the mode for the new file, similar to @code{mode}
+argument of @code{openat}. Different than @code{openat}, @code{openat2}
+returns an error for invalid value (like value larger than @code{07777}).
+
+@item resolve
+This is a bitmask of flags that modify the way in @strong{all} components
+of @code{pathname}. It allows trusted programs to restrict how untrusted
+paths are resolved. The following generic flags are available.
+@table @code
+@item RESOLVE_NO_XDEV
+Disallow traversal of mount points during path resolution (including all
+bind mounts).
+@item RESOLVE_NO_MAGICLINKS
+Disallow all @strong{magic-link} resolution during path resolution. Magic
+links are simbolic link-like objects that are found in @strong{procfs};
+for example the @code{/proc/pid/exe}.
+@item RESOLVE_NO_SYMLINKS
+Disallow resolution of symbolic links during path resolution.
+This option implies @code{RESOLVE_NO_MAGICLINKS}.
+@item RESOLVE_BENEATH
+Do not permit the path resolution to succeed if any component of the
+resolution is not a descendant of the directory indicated by @code{dirfd}.
+@item RESOLVE_IN_ROOT
+Treat the directory referred to by @code{dirfd} as the root directory
+while resolving the @code{pathname}.
+@item RESOLVE_CACHED
+Make the open operation fail unless all path components are already
+present in the kernel's lookup cache.
+@end table
+@end table
+
+For additional information, consult the manual page @manpageurl{openat2,2}.
+@xref{Linux Kernel}.
+@end deftp
+
+
+@deftypefun int openat2 (int @var{dirfd}, const char *@var{pathname}, struct open_how @var{how}, size_t @var{size})
+@standards{Linux, fcntl.h}
+@safety{@mtsafe{}@assafe{}@acsafe{}}
+This function is a extension of the @code{openat} and provides a superset of its
+functionality. @xref{Descriptor-Relative Access}.
+
+The @code{size} define the expected size of @code{how} data structure.
+It is recommended to initialize unused fields to zero, either using
+@code{memset}, or using a structure initializer.
+
+On failure, @code{openat2} returns @math{-1} and sets @code{errno}. The
+following errors are related the way extensibility is handled.
+@table @code
+@item E2BIG
+An extension that the kernel does support was specified in @code{how},
+or a larger struct was used with non-zero fields.
+@item EAGAIN
+@code{how.resolve} contains either RESOLVE_IN_ROOT or RESOLVE_BENEATH, and
+the kernel could not ensure that @code{".."} component did not escape. Or
+@code{RESOLVE_CACHED} was set, and the open operation cannot be performed
+using only cached information.
+@item EINVAL
+And unknown flag or invalid value was used on @code{how}; or @code{mode}
+is non-zero, but @code{how.flags} does not contain @code{O_CREAT} or
+@code{O_TMPFILE}, or @code{size} is smaller than the ones supported
+by the kernel.
+@end table
+
+It can also return all the errors @code{openat} returns, or other errors
+due new fields added by the kernel.
+
+Similar to @code{openat}, @code{openat2} is a cancellation point.
+
+@strong{NB:} Different than other open-like functions, the kernel only
+provides the LFS variant. When the sources are translated with
+@code{_FILE_OFFSET_BITS == 64} this function are not routed a different
+symbol.
+@end deftypefun
+
+
@deftypefn {Obsolete function} int creat (const char *@var{filename}, mode_t @var{mode})
@standards{POSIX.1, fcntl.h}
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
@@ -135,6 +135,7 @@ sysdep_headers += \
bits/mman-linux.h \
bits/mman-map-flags-generic.h \
bits/mman-shared.h \
+ bits/openat2.h \
bits/procfs-extra.h \
bits/procfs-id.h \
bits/procfs-prregset.h \
@@ -606,6 +607,7 @@ sysdep_routines += \
internal_statvfs \
open64_nocancel \
open_nocancel \
+ openat2 \
openat64_nocancel \
openat_nocancel \
pread64_nocancel \
@@ -626,7 +628,19 @@ tests += \
tst-fallocate64 \
tst-getcwd-smallbuff \
tst-o_path-locks \
+ tst-openat2 \
# tests
+
+tests-special += \
+ $(objpfx)tst-openat2-consts.out \
+ # tests-special
+$(objpfx)tst-openat2-consts.out: ../sysdeps/unix/sysv/linux/tst-openat2-consts.py
+ $(sysdeps-linux-python) \
+ ../sysdeps/unix/sysv/linux/tst-openat2-consts.py \
+ $(sysdeps-linux-python-cc) \
+ < /dev/null > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-openat2-consts.out: $(sysdeps-linux-python-deps)
+
endif
ifeq ($(subdir),elf)
@@ -331,6 +331,7 @@ libc {
GLIBC_2.41 {
sched_getattr;
sched_setattr;
+ openat2;
}
GLIBC_PRIVATE {
# functions used in other libraries
@@ -2748,5 +2748,6 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -3095,6 +3095,7 @@ GLIBC_2.4 wcstold F
GLIBC_2.4 wcstold_l F
GLIBC_2.4 wprintf F
GLIBC_2.4 wscanf F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2509,5 +2509,6 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -2801,6 +2801,7 @@ GLIBC_2.4 xdrstdio_create F
GLIBC_2.4 xencrypt F
GLIBC_2.4 xprt_register F
GLIBC_2.4 xprt_unregister F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2798,6 +2798,7 @@ GLIBC_2.4 xdrstdio_create F
GLIBC_2.4 xencrypt F
GLIBC_2.4 xprt_register F
GLIBC_2.4 xprt_unregister F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -452,6 +452,28 @@ extern int name_to_handle_at (int __dfd, const char *__name,
extern int open_by_handle_at (int __mountdirfd, struct file_handle *__handle,
int __flags);
+#ifdef __has_include
+# if __has_include ("linux/openat2.h")
+# include "linux/openat2.h"
+# define __glibc_has_open_how 1
+# endif
+#endif
+
+#include <bits/openat2.h>
+
+/* Similar to `openat' but the arguments are packed on HOW with the size
+ USIZE. If flags and mode from HOW are non-zero, then openat2 operates
+ like openat.
+
+ Unlike openat2, unknown or invalid flags result in an error (EINVAL),
+ rather than being ignored. The mode must be zero unless one O_CREAT
+ or O_TMPFILE are set.
+
+ The kernel does not support legacy non-LFS interface. */
+extern int openat2 (int __dfd, const char *__filename, struct open_how *__how,
+ size_t __usize)
+ __nonnull ((2, 3));
+
#endif /* use GNU */
__END_DECLS
new file mode 100644
@@ -0,0 +1,61 @@
+/* openat2 definition. Linux specific.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _FCNTL_H
+# error "Never use <bits/openat2.h> directly; include <fcntl.h> instead."
+#endif
+
+#ifndef __glibc_has_open_how
+/* Arguments for how openat2 should open the target path. */
+struct open_how
+{
+ __uint64_t flags;
+ __uint64_t mode;
+ __uint64_t resolve;
+};
+#endif
+
+/* how->resolve flags for openat2. */
+#ifndef RESOLVE_NO_XDEV
+# define RESOLVE_NO_XDEV 0x01 /* Block mount-point crossings
+ (includes bind-mounts). */
+#endif
+#ifndef RESOLVE_NO_MAGICLINKS
+# define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
+ "magic-links". */
+#endif
+#ifndef RESOLVE_NO_SYMLINKS
+# define RESOLVE_NO_SYMLINKS 0x04 /* Block traversal through all symlinks
+ (implies OEXT_NO_MAGICLINKS). */
+#endif
+#ifndef RESOLVE_BENEATH
+# define RESOLVE_BENEATH 0x08 /* Block "lexical" trickery like
+ "..", symlinks, and absolute
+ paths which escape the dirfd. */
+#endif
+#ifndef RESOLVE_IN_ROOT
+# define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".."
+ be scoped inside the dirfd
+ (similar to chroot). */
+#endif
+#ifndef RESOLVE_CACHED
+# define RESOLVE_CACHED 0x20 /* Only complete if resolution can be
+ completed through cached lookup. May
+ return -EAGAIN if that's not
+ possible. */
+#endif
@@ -2785,5 +2785,6 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -2821,6 +2821,7 @@ GLIBC_2.4 sys_errlist D 0x400
GLIBC_2.4 sys_nerr D 0x4
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -3005,6 +3005,7 @@ GLIBC_2.4 sys_errlist D 0x210
GLIBC_2.4 sys_nerr D 0x4
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2269,5 +2269,6 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -2781,6 +2781,7 @@ GLIBC_2.4 xdrstdio_create F
GLIBC_2.4 xencrypt F
GLIBC_2.4 xprt_register F
GLIBC_2.4 xprt_unregister F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2948,6 +2948,7 @@ GLIBC_2.4 sys_errlist D 0x210
GLIBC_2.4 sys_nerr D 0x4
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2834,5 +2834,6 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -2831,5 +2831,6 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -2909,6 +2909,7 @@ GLIBC_2.4 renameat F
GLIBC_2.4 symlinkat F
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2907,6 +2907,7 @@ GLIBC_2.4 renameat F
GLIBC_2.4 symlinkat F
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2915,6 +2915,7 @@ GLIBC_2.4 renameat F
GLIBC_2.4 symlinkat F
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2817,6 +2817,7 @@ GLIBC_2.4 renameat F
GLIBC_2.4 symlinkat F
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2873,5 +2873,6 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
new file mode 100644
@@ -0,0 +1,29 @@
+/* Linux openat2 syscall implementation.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <fcntl.h>
+#include <bits/openat2.h>
+#include <sysdep-cancel.h>
+
+int
+__openat2 (int dfd, const char *filename, struct open_how *how,
+ size_t usize)
+{
+ return SYSCALL_CANCEL (openat2, dfd, filename, how, usize);
+}
+weak_alias (__openat2, openat2)
@@ -2259,5 +2259,6 @@ GLIBC_2.40 getcontext F
GLIBC_2.40 makecontext F
GLIBC_2.40 setcontext F
GLIBC_2.40 swapcontext F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -3138,6 +3138,7 @@ GLIBC_2.4 wcstold F
GLIBC_2.4 wcstold_l F
GLIBC_2.4 wprintf F
GLIBC_2.4 wscanf F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -3183,6 +3183,7 @@ GLIBC_2.4 wcstold F
GLIBC_2.4 wcstold_l F
GLIBC_2.4 wprintf F
GLIBC_2.4 wscanf F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2892,6 +2892,7 @@ GLIBC_2.4 wcstold F
GLIBC_2.4 wcstold_l F
GLIBC_2.4 wprintf F
GLIBC_2.4 wscanf F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2968,5 +2968,6 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -2512,5 +2512,6 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
GLIBC_2.40 __riscv_hwprobe F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -2712,5 +2712,6 @@ GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
GLIBC_2.40 __riscv_hwprobe F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
@@ -3136,6 +3136,7 @@ GLIBC_2.4 wcstold F
GLIBC_2.4 wcstold_l F
GLIBC_2.4 wprintf F
GLIBC_2.4 wscanf F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2929,6 +2929,7 @@ GLIBC_2.4 wcstold F
GLIBC_2.4 wcstold_l F
GLIBC_2.4 wprintf F
GLIBC_2.4 wscanf F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2828,6 +2828,7 @@ GLIBC_2.4 sys_errlist D 0x210
GLIBC_2.4 sys_nerr D 0x4
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2825,6 +2825,7 @@ GLIBC_2.4 sys_errlist D 0x210
GLIBC_2.4 sys_nerr D 0x4
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -3157,6 +3157,7 @@ GLIBC_2.4 wcstold F
GLIBC_2.4 wcstold_l F
GLIBC_2.4 wprintf F
GLIBC_2.4 wscanf F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2793,6 +2793,7 @@ GLIBC_2.4 sys_errlist D 0x430
GLIBC_2.4 sys_nerr D 0x4
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
new file mode 100755
@@ -0,0 +1,63 @@
+#!/usr/bin/python3
+# Test that glibc's sys/openat2.h constants match the kernel's.
+# Copyright (C) 2024 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+
+import glibcextract
+import glibcsyscalls
+
+
+def main():
+ """The main entry point."""
+ parser = argparse.ArgumentParser(
+ description="Test that glibc's sys/openat2.h constants "
+ "match the kernel's.")
+ parser.add_argument('--cc', metavar='CC',
+ help='C compiler (including options) to use')
+ args = parser.parse_args()
+
+ if glibcextract.compile_c_snippet(
+ '#include <linux/openat2.h>',
+ args.cc).returncode != 0:
+ sys.exit (77)
+
+ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+ # Constants in glibc were updated to match Linux v6.8. When glibc
+ # constants are updated this value should be updated to match the
+ # released kernel version from which the constants were taken.
+ linux_version_glibc = (6, 8)
+ def check(cte, exclude=None):
+ return glibcextract.compare_macro_consts(
+ '#define _FCNTL_H\n'
+ '#include <stdint.h>\n'
+ '#include <bits/openat2.h>\n',
+ '#include <asm/fcntl.h>\n'
+ '#include <linux/openat2.h>\n',
+ args.cc,
+ cte,
+ exclude,
+ linux_version_glibc > linux_version_headers,
+ linux_version_headers > linux_version_glibc)
+
+ status = check('RESOLVE.*')
+ sys.exit(status)
+
+if __name__ == '__main__':
+ main()
new file mode 100644
@@ -0,0 +1,259 @@
+/* Linux openat2 tests.
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+/* openat2 always return a file descriptor in LFS mode. */
+#define _FILE_OFFSET_BITS 64
+
+#include <array_length.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/xunistd.h>
+
+static int dir_fd;
+
+static void
+do_prepare (int argc, char *argv[])
+{
+ char *temp_dir = support_create_temp_directory ("tst-openat2");
+ dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
+}
+#define PREPARE do_prepare
+
+static int
+do_test_struct (void)
+{
+ static struct struct_test
+ {
+ struct open_how_ext
+ {
+ struct open_how inner;
+ int extra1;
+ int extra2;
+ int extra3;
+ } arg;
+ size_t size;
+ int err;
+ } tests[] =
+ {
+ {
+ /* Zero size. */
+ .arg.inner.flags = O_RDONLY,
+ .size = 0,
+ .err = EINVAL,
+ },
+ {
+ /* Normal struct. */
+ .arg.inner.flags = O_RDONLY,
+ .size = sizeof (struct open_how),
+ },
+ {
+ /* Larger struct, zeroed out the unused values. */
+ .arg.inner.flags = O_RDONLY,
+ .size = sizeof (struct open_how_ext),
+ },
+ {
+ /* Larger struct, non-zeroed out the unused values. */
+ .arg.inner.flags = O_RDONLY,
+ .arg.extra1 = 0xdeadbeef,
+ .size = sizeof (struct open_how_ext),
+ .err = E2BIG,
+ },
+ {
+ /* Larger struct, non-zeroed out the unused values. */
+ .arg.inner.flags = O_RDONLY,
+ .arg.extra2 = 0xdeadbeef,
+ .size = sizeof (struct open_how_ext),
+ .err = E2BIG,
+ },
+ };
+
+ for (struct struct_test *t = tests; t != array_end (tests); t++)
+ {
+ int fd = openat2 (AT_FDCWD, ".", (struct open_how *) &t->arg, t->size);
+ if (fd == -1 && errno == ENOSYS)
+ FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
+
+ if (t->err != 0)
+ {
+ TEST_COMPARE (fd, -1);
+ TEST_COMPARE (errno, t->err);
+ }
+ else
+ TEST_VERIFY (fd >= 0);
+ }
+
+ return 0;
+}
+
+static int
+do_test_flags (void)
+{
+ static struct flag_test
+ {
+ struct open_how how;
+ int err;
+ } tests[] =
+ {
+ /* O_TMPFILE is incompatible with O_PATH and O_CREAT. */
+ { .how.flags = O_TMPFILE | O_PATH | O_RDWR, .err = EINVAL },
+ { .how.flags = O_TMPFILE | O_CREAT | O_RDWR, .err = EINVAL },
+
+ /* O_PATH only permits certain other flags to be set ... */
+ { .how.flags = O_PATH | O_CLOEXEC },
+ { .how.flags = O_PATH | O_DIRECTORY },
+ { .how.flags = O_PATH | O_NOFOLLOW },
+ /* ... and others are absolutely not permitted. */
+ { .how.flags = O_PATH | O_RDWR, .err = EINVAL },
+ { .how.flags = O_PATH | O_CREAT, .err = EINVAL },
+ { .how.flags = O_PATH | O_EXCL, .err = EINVAL },
+ { .how.flags = O_PATH | O_NOCTTY, .err = EINVAL },
+ { .how.flags = O_PATH | O_DIRECT, .err = EINVAL },
+
+ /* ->mode must only be set with O_{CREAT,TMPFILE}. */
+ { .how.flags = O_RDONLY, .how.mode = 0600, .err = EINVAL },
+ { .how.flags = O_PATH, .how.mode = 0600, .err = EINVAL },
+ { .how.flags = O_CREAT, .how.mode = 0600 },
+ { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0600 },
+ /* ->mode must only contain 0777 bits. */
+ { .how.flags = O_CREAT, .how.mode = 0xFFFF, .err = EINVAL },
+ { .how.flags = O_CREAT, .how.mode = 0xC000000000000000ULL, .err = EINVAL },
+ { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x1337, .err = EINVAL },
+ { .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x0000A00000000000ULL,
+ .err = EINVAL },
+
+ /* ->resolve flags must not conflict. */
+ { .how.flags = O_RDONLY,
+ .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
+ .err = EINVAL },
+
+ /* ->resolve must only contain RESOLVE_* flags. */
+ { .how.flags = O_RDONLY,
+ .how.resolve = 0x1337, .err = EINVAL },
+ { .how.flags = O_CREAT,
+ .how.resolve = 0x1337, .err = EINVAL },
+ { .how.flags = O_TMPFILE | O_RDWR,
+ .how.resolve = 0x1337, .err = EINVAL },
+ { .how.flags = O_PATH,
+ .how.resolve = 0x1337, .err = EINVAL },
+
+ /* currently unknown upper 32 bit rejected. */
+ { .how.flags = O_RDONLY | (1ULL << 63),
+ .how.resolve = 0, .err = EINVAL },
+ };
+
+ for (struct flag_test *t = tests; t != array_end (tests); t++)
+ {
+ char *path;
+ if (t->how.flags & O_CREAT)
+ {
+ int temp_fd = create_temp_file ("tst-openat2.", &path);
+ TEST_VERIFY_EXIT (temp_fd != -1);
+ xunlink (path);
+ }
+ else
+ path = (char *) ".";
+
+ int fd = openat2 (AT_FDCWD, path, &t->how, sizeof (struct open_how));
+ if (fd != 0 && errno == EOPNOTSUPP)
+ {
+ /* Skip the testcase if FS does not support the operation (e.g.
+ valid O_TMPFILE on NFS). */
+ continue;
+ }
+
+ if (t->err != 0)
+ {
+ TEST_COMPARE (fd, -1);
+ TEST_COMPARE (errno, t->err);
+ }
+ else
+ TEST_VERIFY (fd >= 0);
+ }
+
+ return 0;
+}
+
+static int
+do_test_basic (void)
+{
+ int fd;
+
+ fd = openat2 (dir_fd,
+ "some-file",
+ &(struct open_how)
+ {
+ .flags = O_CREAT|O_RDWR|O_EXCL,
+ .mode = 0666,
+ },
+ sizeof (struct open_how));
+ TEST_VERIFY (fd != -1);
+
+ xwrite (fd, "hello", 5);
+
+ /* Before closing the file, try using this file descriptor to open
+ another file. This must fail. */
+ {
+ int fd2 = openat2 (fd,
+ "should-not-work",
+ &(struct open_how)
+ {
+ .flags = O_CREAT|O_RDWR|O_EXCL,
+ .mode = 0666,
+ },
+ sizeof (struct open_how));
+ TEST_COMPARE (fd2, -1);
+ TEST_COMPARE (errno, ENOTDIR);
+ }
+
+ /* Remove the created file. */
+ int cwdfd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
+ TEST_COMPARE (fchdir (dir_fd), 0);
+ xunlink ("some-file");
+ TEST_COMPARE (fchdir (cwdfd), 0);
+
+ xclose (dir_fd);
+ xclose (cwdfd);
+
+ fd = openat2 (dir_fd,
+ "some-file",
+ &(struct open_how)
+ {
+ .flags = O_CREAT|O_RDWR|O_EXCL,
+ .mode = 0666,
+ },
+ sizeof (struct open_how));
+ TEST_COMPARE (fd, -1);
+ TEST_COMPARE (errno, EBADF);
+
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ do_test_struct ();
+ do_test_flags ();
+ do_test_basic ();
+
+ return 0;
+}
+
+#include <support/test-driver.c>
@@ -2744,6 +2744,7 @@ GLIBC_2.4 sys_errlist D 0x420
GLIBC_2.4 sys_nerr D 0x4
GLIBC_2.4 unlinkat F
GLIBC_2.4 unshare F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F
GLIBC_2.5 __readlinkat_chk F
@@ -2763,5 +2763,6 @@ GLIBC_2.39 stdc_trailing_zeros_ui F
GLIBC_2.39 stdc_trailing_zeros_ul F
GLIBC_2.39 stdc_trailing_zeros_ull F
GLIBC_2.39 stdc_trailing_zeros_us F
+GLIBC_2.41 openat2 F
GLIBC_2.41 sched_getattr F
GLIBC_2.41 sched_setattr F