kern/176233: New dup3() implementation for FreeBSD
Jukka Ukkonen
jau at iki.fi
Mon Feb 18 10:00:02 UTC 2013
>Number: 176233
>Category: kern
>Synopsis: New dup3() implementation for FreeBSD
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Mon Feb 18 10:00:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator: Jukka Ukkonen
>Release: 9.1-STABLE
>Organization:
-----
>Environment:
FreeBSD sleipnir 9.1-STABLE FreeBSD 9.1-STABLE #0 r246937M: Mon Feb 18 08:44:50 EET 2013 root at sleipnir:/usr/obj/usr/src/sys/Sleipnir amd64
>Description:
Because dup3() with the additional flags argument would be useful in general,
here is an implementation for FreeBSD.
Some other UNIX style systems (at least NetBSD and Linux) already have a similar
function. So, there is also the enhanced portability point of view driving this.
>How-To-Repeat:
No actual problem.
Only a nifty add-on feature and enhanced portability.
>Fix:
Find a patch attached.
Patch attached with submission follows:
--- ./lib/libc/gen/Makefile.inc.orig 2013-02-16 09:50:42.000000000 +0200
+++ ./lib/libc/gen/Makefile.inc 2013-02-16 09:50:59.000000000 +0200
@@ -10,7 +10,8 @@
alarm.c arc4random.c assert.c aux.c basename.c check_utility_compat.c \
clock.c closedir.c confstr.c \
crypt.c ctermid.c daemon.c devname.c dirname.c disklabel.c \
- dlfcn.c drand48.c elf_utils.c erand48.c err.c errlst.c errno.c \
+ dlfcn.c drand48.c dup3.c \
+ elf_utils.c erand48.c err.c errlst.c errno.c \
exec.c fdevname.c feature_present.c fmtcheck.c fmtmsg.c fnmatch.c \
fpclassify.c frexp.c fstab.c ftok.c fts.c fts-compat.c ftw.c \
getbootfile.c getbsize.c \
--- ./lib/libc/gen/Symbol.map.orig 2013-02-16 09:52:41.000000000 +0200
+++ ./lib/libc/gen/Symbol.map 2013-02-16 09:53:25.000000000 +0200
@@ -382,6 +382,7 @@
FBSD_1.3 {
fdlopen;
__FreeBSD_libc_enter_restricted_mode;
+ dup3;
getcontextx;
gid_from_group;
nvis;
--- ./include/unistd.h.orig 2013-02-16 10:02:01.000000000 +0200
+++ ./include/unistd.h 2013-02-16 10:03:13.000000000 +0200
@@ -326,6 +326,9 @@
void closefrom(int);
int dup(int);
int dup2(int, int);
+#if __BSD_VISIBLE
+int dup3(int, int, int);
+#endif
int execl(const char *, const char *, ...);
int execle(const char *, const char *, ...);
int execlp(const char *, const char *, ...);
--- lib/libc/sys/Makefile.inc.orig 2013-02-16 10:34:41.000000000 +0200
+++ lib/libc/sys/Makefile.inc 2013-02-16 22:09:12.000000000 +0200
@@ -132,7 +132,7 @@
MLINKS+=clock_gettime.2 clock_getres.2 clock_gettime.2 clock_settime.2
MLINKS+=cpuset.2 cpuset_getid.2 cpuset.2 cpuset_setid.2
MLINKS+=cpuset_getaffinity.2 cpuset_setaffinity.2
-MLINKS+=dup.2 dup2.2
+MLINKS+=dup.2 dup2.2 dup3.2
MLINKS+=execve.2 fexecve.2
MLINKS+=extattr_get_file.2 extattr.2 \
extattr_get_file.2 extattr_delete_fd.2 \
--- lib/libc/sys/dup.2.orig 2013-02-16 09:59:09.000000000 +0200
+++ lib/libc/sys/dup.2 2013-02-18 11:28:21.000000000 +0200
@@ -43,6 +43,9 @@
.Fn dup "int oldd"
.Ft int
.Fn dup2 "int oldd" "int newd"
+.In fcntl.h
+.Ft int
+.Fn dup3 "int oldd" "int newd" "int flags"
.Sh DESCRIPTION
The
.Fn dup
@@ -116,6 +119,72 @@
.Fn dup2
is successful, and does nothing.
.Pp
+The
+.Fn dup3
+function is otherwise much the same as
+.Fn dup2
+with the added ability to automatically set certain
+important flags to the resulting new file descriptor.
+.br
+By setting the bit
+.Dv O_CLOEXEC
+in the flags one can mark the resulting file descriptor be
+automatically closed during
+.Fn execve
+and other functions in the
+.Fn exec*
+family.
+Since this feature is activated atomically inside the kernel
+there is no risk that even in a threaded code another thread
+could call any of the
+.Fn exec*
+functions before the descriptor has been marked to be closed.
+.br
+Setting the bit
+.Dv O_NONBLOCK
+in the flags marks the resulting file descriptor for non-blocking I/O.
+.sp
+There a couple of features in
+.Fn dup3
+which can have an impact on portability.
+.br
+Currently this implementation of
+.Fn dup3
+does not support the
+.Nx
+feature
+.Dv O_NOSIGPIPE .
+.br
+Because the
+.Fx
+kernel can properly handle the case when
+.Fa oldd
+==
+.Fa newd
+this implementation of
+.Fn dup3
+will not return an error like
+.Fn dup3
+on Linux when it receives two equal file descriptors as arguments.
+Instead this implementation intentionally behaves like
+.Fn dup3
+in
+.Nx
+and sets the flags on the resulting file descriptor.
+Thus any code that has worked on Linux should
+work fine also on
+.Fx
+and/or
+.Nx ,
+but porting to the other direction may cause hiccups.
+.Pp
+Unlike the other two functions
+.Fn dup3
+is not implemented as a genuine system call but as a normal library function
+depending on the features provided by the
+.Fn fcntl
+system call.
+.Pp
The related
.Xr cap_new 2
system call allows file descriptors to be duplicated with restrictions on
@@ -138,6 +207,7 @@
.It Bq Er EMFILE
Too many descriptors are active.
.El
+.sp
The
.Fn dup2
system call fails if:
@@ -149,6 +219,26 @@
.Fa newd
argument is negative or exceeds the maximum allowable descriptor number
.El
+.sp
+The
+.Fn dup3
+function fails if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa oldd
+argument is not a valid active descriptor or the
+.Fa newd
+argument is negative or exceeds the maximum allowable descriptor number
+.It Bq Er EINVAL
+The
+.Fa flags
+argument containes unsupported bits.
+Currently the only accepted bits are
+.Dv O_CLOEXEC
+and
+.Dv O_NONBLOCK .
+.El
.Sh SEE ALSO
.Xr accept 2 ,
.Xr cap_new 2 ,
@@ -166,6 +256,13 @@
.Fn dup2
system calls are expected to conform to
.St -p1003.1-90 .
+.br
+Currently the
+.Fn dup3
+entry is not dictated by any standard.
+It is simply a natural extension the other two variants and
+a compatibility feature to match a similar extension in other
+UNIX like systems.
.Sh HISTORY
The
.Fn dup
@@ -173,3 +270,9 @@
.Fn dup2
functions appeared in
.At v7 .
+.br
+The
+.Fn dup3
+function appeared in
+.Fx 9.1
+STABLE branch.
--- /dev/null 2013-02-16 22:00:01.000000000 +0200
+++ lib/libc/gen/dup3.c 2013-02-16 22:03:55.000000000 +0200
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 2012 Jukka A. Ukkonen
+ * All rights reserved.
+ *
+ * This software was developed by Jukka Ukkonen for FreeBSD.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "un-namespace.h"
+
+/*
+ * A bunch of checks just in case someone
+ * tries to compile this on a too old system.
+ */
+
+#if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
+# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
+#endif
+
+#if !defined(F_DUP2FD_CLOEXEC)
+# error Neither F_DUP2FD_CLOEXEC nor _F_DUP2FD_CLOEXEC defined!
+#endif
+
+#if !defined(F_DUP2FD)
+# error F_DUP2FD not defined!
+#endif
+
+#if !defined(O_CLOEXEC)
+# error O_CLOEXEC not defined!
+#endif
+
+/*
+ * In case FreeBSD ever becomes O_NOSIGPIPE aware,
+ * we will instantly start using it.
+ */
+
+#if !defined(O_NOSIGPIPE)
+# define O_NOSIGPIPE 0
+#endif
+
+int
+__dup3 (oldfd, newfd, flags)
+ int oldfd;
+ int newfd;
+ int flags;
+{
+ int how;
+ int ret;
+
+#if 0
+ /*
+ * This would be how Linux does it
+ * in pointlessly restrictive style.
+ * NetBSD does not do this.
+ * FreeBSD can also handle this case
+ * properly.
+ * ==> Anything which works on Linux
+ * will work also on {Free,Net}BSD.
+ * BSD code on Linux may experience
+ * hiccups, if someone relies on
+ * oldfd == newfd.
+ */
+
+ if (oldfd == newfd) {
+ errno = EINVAL;
+ return (-1);
+ }
+#endif
+
+ if (flags & ~(O_CLOEXEC | O_NONBLOCK | O_NOSIGPIPE)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ how = (flags & O_CLOEXEC) ? F_DUP2FD_CLOEXEC : F_DUP2FD;
+
+ ret = _fcntl (oldfd, how, newfd);
+
+ if (ret < 0)
+ return (-1);
+
+ newfd = ret;
+
+ if (flags & (O_NONBLOCK | O_NOSIGPIPE)) {
+ int flags2;
+
+ flags2 = _fcntl (newfd, F_GETFL, 0);
+ flags2 |= (flags & (O_NONBLOCK | O_NOSIGPIPE));
+ (void) _fcntl (newfd, F_SETFL, flags2);
+ }
+
+ return (newfd);
+}
+
+__weak_reference(__dup3, dup3);
+__weak_reference(__dup3, _dup3);
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list