git: ca39124ff3bb - stable/13 - Add kern_openatfp(9)

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 31 Jan 2024 01:02:06 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=ca39124ff3bbebc34a62f36b4a231976e2de9f10

commit ca39124ff3bbebc34a62f36b4a231976e2de9f10
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-01-20 20:34:46 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-01-30 20:24:33 +0000

    Add kern_openatfp(9)
    
    (cherry picked from commit c662306e19ce60d0f5e5e32a22ddcd5c79a90849)
---
 sys/kern/vfs_syscalls.c | 39 ++++++++++++++++++++++++++++++++++++---
 sys/sys/syscallsubr.h   |  2 ++
 2 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 494bae687406..7dcdaa66adb8 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -1103,9 +1103,14 @@ sys_openat(struct thread *td, struct openat_args *uap)
 	    uap->mode));
 }
 
-int
-kern_openat(struct thread *td, int dirfd, const char *path,
-    enum uio_seg pathseg, int flags, int mode)
+/*
+ * If fpp != NULL, opened file is not installed into the file
+ * descriptor table, instead it is returned in *fpp.  This is
+ * incompatible with fdopen(), in which case we return EINVAL.
+ */
+static int
+openatfp(struct thread *td, int dirfd, const char *path,
+    enum uio_seg pathseg, int flags, int mode, struct file **fpp)
 {
 	struct proc *p;
 	struct filedesc *fdp;
@@ -1179,6 +1184,7 @@ kern_openat(struct thread *td, int dirfd, const char *path,
 		if ((nd.ni_resflags & NIRES_STRICTREL) == 0 &&
 		    (error == ENODEV || error == ENXIO) &&
 		    td->td_dupfd >= 0) {
+			MPASS(fpp == NULL);
 			error = dupfdopen(td, fdp, td->td_dupfd, flags, error,
 			    &indx);
 			if (error == 0)
@@ -1220,6 +1226,13 @@ kern_openat(struct thread *td, int dirfd, const char *path,
 			goto bad;
 	}
 success:
+	if (fpp != NULL) {
+		MPASS(error == 0);
+		NDFREE_IOCTLCAPS(&nd);
+		*fpp = fp;
+		return (0);
+	}
+
 	/*
 	 * If we haven't already installed the FD (for dupfdopen), do so now.
 	 */
@@ -1249,6 +1262,26 @@ bad:
 	return (error);
 }
 
+int
+kern_openat(struct thread *td, int dirfd, const char *path,
+    enum uio_seg pathseg, int flags, int mode)
+{
+	return (openatfp(td, dirfd, path, pathseg, flags, mode, NULL));
+}
+
+int
+kern_openatfp(struct thread *td, int dirfd, const char *path,
+    enum uio_seg pathseg, int flags, int mode, struct file **fpp)
+{
+	int error, old_dupfd;
+
+	old_dupfd = td->td_dupfd;
+	td->td_dupfd = -1;
+	error = openatfp(td, dirfd, path, pathseg, flags, mode, fpp);
+	td->td_dupfd = old_dupfd;
+	return (error);
+}
+
 #ifdef COMPAT_43
 /*
  * Create a file.
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index 02e5b1a4c077..77c16d8fffc0 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -230,6 +230,8 @@ int	kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap,
 	    long *ploff);
 int	kern_openat(struct thread *td, int dirfd, const char *path,
 	    enum uio_seg pathseg, int flags, int mode);
+int	kern_openatfp(struct thread *td, int dirfd, const char *path,
+	    enum uio_seg pathseg, int flags, int mode, struct file **fpp);
 int	kern_pathconf(struct thread *td, const char *path,
 	    enum uio_seg pathseg, int name, u_long flags, long *valuep);
 int	kern_pipe(struct thread *td, int fildes[2], int flags,