From c6e801f48ba2ad620ea6c8fe8899fb80af386135 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Sun, 5 Apr 2020 15:54:29 -0700 Subject: [PATCH] unix: add openat2 for linux openat2 is a new syscall added to Linux 5.6. It provides a superset of openat(2) functionality, providing a way to extend it in the future, and (for now) adding flags telling the kernel how to resolve the path. For more info on openat2, see https://lwn.net/Articles/803237/ A primitive test case is added to check that Openat2 works as it should. Tested to skip on kernel 5.5 and pass on 5.6. Change-Id: Ib8bbd71791762f043200543cecdea16d2fd3c81d Signed-off-by: Kir Kolyshkin Reviewed-on: https://go-review.googlesource.com/c/sys/+/227280 Run-TryBot: Tobias Klauser TryBot-Result: Gobot Gobot Reviewed-by: Tobias Klauser --- unix/linux/types.go | 13 +++++++++++++ unix/syscall_linux.go | 6 ++++++ unix/syscall_linux_test.go | 21 +++++++++++++++++++++ unix/zsyscall_linux.go | 16 ++++++++++++++++ unix/ztypes_linux.go | 16 ++++++++++++++++ 5 files changed, 72 insertions(+) diff --git a/unix/linux/types.go b/unix/linux/types.go index 1e90b2ea..10f1ea46 100644 --- a/unix/linux/types.go +++ b/unix/linux/types.go @@ -106,6 +106,7 @@ struct termios2 { #include #include #include +#include #include #include #include @@ -833,6 +834,18 @@ const ( AT_EACCESS = C.AT_EACCESS ) +type OpenHow C.struct_open_how + +const SizeofOpenHow = C.sizeof_struct_open_how + +const ( + RESOLVE_BENEATH = C.RESOLVE_BENEATH + RESOLVE_IN_ROOT = C.RESOLVE_IN_ROOT + RESOLVE_NO_MAGICLINKS = C.RESOLVE_NO_MAGICLINKS + RESOLVE_NO_SYMLINKS = C.RESOLVE_NO_SYMLINKS + RESOLVE_NO_XDEV = C.RESOLVE_NO_XDEV +) + type PollFd C.struct_pollfd const ( diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go index bbe1abbc..2b151eba 100644 --- a/unix/syscall_linux.go +++ b/unix/syscall_linux.go @@ -133,6 +133,12 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) return openat(dirfd, path, flags|O_LARGEFILE, mode) } +//sys openat2(dirfd int, path string, open_how *OpenHow, size int) (fd int, err error) + +func Openat2(dirfd int, path string, how *OpenHow) (fd int, err error) { + return openat2(dirfd, path, how, SizeofOpenHow) +} + //sys ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go index e572376f..8adb426e 100644 --- a/unix/syscall_linux_test.go +++ b/unix/syscall_linux_test.go @@ -663,3 +663,24 @@ func TestPrctlRetInt(t *testing.T) { t.Fatalf("unexpected return from prctl; got %v, expected %v", v, 1) } } + +func TestOpenat2(t *testing.T) { + how := &unix.OpenHow{ + Flags: unix.O_RDONLY, + Resolve: unix.RESOLVE_NO_MAGICLINKS, + } + fd, err := unix.Openat2(-1, "/proc/self/fd/1", how) + switch err { + case nil: + unix.Close(fd) + t.Fatal("expected ELOOP, got nil") + case unix.ELOOP: + return + case unix.ENOSYS: + t.Skip("old kernel? (need Linux >= 5.6)") + case unix.ENOENT: + t.Skipf("openat2: %v, skipping test", err) + default: + t.Fatalf("unexpected error from openat2: %v", err) + } +} diff --git a/unix/zsyscall_linux.go b/unix/zsyscall_linux.go index fd2dae8e..5c5b7422 100644 --- a/unix/zsyscall_linux.go +++ b/unix/zsyscall_linux.go @@ -83,6 +83,22 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func openat2(dirfd int, path string, open_how *OpenHow, size int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT2, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(open_how)), uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0) diff --git a/unix/ztypes_linux.go b/unix/ztypes_linux.go index 9c43c26f..781a5eae 100644 --- a/unix/ztypes_linux.go +++ b/unix/ztypes_linux.go @@ -691,6 +691,22 @@ const ( AT_EACCESS = 0x200 ) +type OpenHow struct { + Flags uint64 + Mode uint64 + Resolve uint64 +} + +const SizeofOpenHow = 0x18 + +const ( + RESOLVE_BENEATH = 0x8 + RESOLVE_IN_ROOT = 0x10 + RESOLVE_NO_MAGICLINKS = 0x2 + RESOLVE_NO_SYMLINKS = 0x4 + RESOLVE_NO_XDEV = 0x1 +) + type PollFd struct { Fd int32 Events int16