From owner-freebsd-bugs@FreeBSD.ORG Mon Feb 18 10:00:02 2013 Return-Path: Delivered-To: freebsd-bugs@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 7DFB1DC for ; Mon, 18 Feb 2013 10:00:02 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 61D7E8B2 for ; Mon, 18 Feb 2013 10:00:02 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r1IA01cr048151 for ; Mon, 18 Feb 2013 10:00:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r1IA01ba048150; Mon, 18 Feb 2013 10:00:01 GMT (envelope-from gnats) Resent-Date: Mon, 18 Feb 2013 10:00:01 GMT Resent-Message-Id: <201302181000.r1IA01ba048150@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Jukka Ukkonen Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 25DBAE90 for ; Mon, 18 Feb 2013 09:54:40 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22]) by mx1.freebsd.org (Postfix) with ESMTP id F2F91882 for ; Mon, 18 Feb 2013 09:54:39 +0000 (UTC) Received: from red.freebsd.org (localhost [127.0.0.1]) by red.freebsd.org (8.14.5/8.14.5) with ESMTP id r1I9sdec061016 for ; Mon, 18 Feb 2013 09:54:39 GMT (envelope-from nobody@red.freebsd.org) Received: (from nobody@localhost) by red.freebsd.org (8.14.5/8.14.5/Submit) id r1I9sdkr061015; Mon, 18 Feb 2013 09:54:39 GMT (envelope-from nobody) Message-Id: <201302180954.r1I9sdkr061015@red.freebsd.org> Date: Mon, 18 Feb 2013 09:54:39 GMT From: Jukka Ukkonen To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-3.1 Subject: kern/176233: New dup3() implementation for FreeBSD X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Feb 2013 10:00:02 -0000 >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@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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#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: