Introduce a new F_DUP2FD command to fcntl(2), for compatibility with

Solaris and AIX.
fcntl(fd, F_DUP2FD, arg) and dup2(fd, arg) are functionnaly equivalent.
Document it.
Add some regression tests (identical to the dup2(2) regression tests).

PR:		120233
Submitted by:	Jukka Ukkonen
Approved by:	rwaston (mentor)
MFC after:	1 month
This commit is contained in:
Antoine Brodin 2008-03-08 22:02:21 +00:00
parent 40f9a23605
commit e3ad7f6626
4 changed files with 115 additions and 4 deletions

View File

@ -28,7 +28,7 @@
.\" @(#)fcntl.2 8.2 (Berkeley) 1/12/94 .\" @(#)fcntl.2 8.2 (Berkeley) 1/12/94
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd January 12, 1994 .Dd March 8, 2008
.Dt FCNTL 2 .Dt FCNTL 2
.Os .Os
.Sh NAME .Sh NAME
@ -78,6 +78,18 @@ is set to remain open across
.Xr execve 2 .Xr execve 2
system calls. system calls.
.El .El
.It Dv F_DUP2FD
It is functionally equivalent to
.Bd -literal -offset indent
dup2(fd, arg)
.Ed
.Pp
The
.Dv F_DUP2FD
constant is not portable, so it should not be used if portability is needed.
Use
.Fn dup2
instead.
.It Dv F_GETFD .It Dv F_GETFD
Get the close-on-exec flag associated with the file descriptor Get the close-on-exec flag associated with the file descriptor
.Fa fd .Fa fd
@ -389,6 +401,9 @@ as follows:
.Bl -tag -width F_GETOWNX -offset indent .Bl -tag -width F_GETOWNX -offset indent
.It Dv F_DUPFD .It Dv F_DUPFD
A new file descriptor. A new file descriptor.
.It Dv F_DUP2FD
A file descriptor equal to
.Fa arg .
.It Dv F_GETFD .It Dv F_GETFD
Value of flag (only the low-order bit is defined). Value of flag (only the low-order bit is defined).
.It Dv F_GETFL .It Dv F_GETFL
@ -432,6 +447,14 @@ is not a valid open file descriptor.
The argument The argument
.Fa cmd .Fa cmd
is is
.Dv F_DUP2FD ,
and
.Fa arg
is not a valid file descriptor.
.Pp
The argument
.Fa cmd
is
.Dv F_SETLK .Dv F_SETLK
or or
.Dv F_SETLKW , .Dv F_SETLKW ,
@ -495,6 +518,8 @@ The argument
.Fa cmd .Fa cmd
is is
.Dv F_DUPFD .Dv F_DUPFD
or
.Dv F_DUP2FD
and the maximum number of file descriptors permitted for the and the maximum number of file descriptors permitted for the
process are already in use, process are already in use,
or no file descriptors greater than or equal to or no file descriptors greater than or equal to
@ -567,6 +592,7 @@ for the reasons as stated in
.Xr tcgetpgrp 3 . .Xr tcgetpgrp 3 .
.Sh SEE ALSO .Sh SEE ALSO
.Xr close 2 , .Xr close 2 ,
.Xr dup2 2 ,
.Xr execve 2 , .Xr execve 2 ,
.Xr flock 2 , .Xr flock 2 ,
.Xr getdtablesize 2 , .Xr getdtablesize 2 ,
@ -575,8 +601,18 @@ for the reasons as stated in
.Xr lockf 3 , .Xr lockf 3 ,
.Xr tcgetpgrp 3 , .Xr tcgetpgrp 3 ,
.Xr tcsetpgrp 3 .Xr tcsetpgrp 3
.Sh STANDARDS
The
.Dv F_DUP2FD
constant is non portable.
It is provided for compatibility with AIX and Solaris.
.Sh HISTORY .Sh HISTORY
The The
.Fn fcntl .Fn fcntl
system call appeared in system call appeared in
.Bx 4.2 . .Bx 4.2 .
.Pp
The
.Dv F_DUP2FD
constant first appeared in
.Fx 7.1 .

View File

@ -397,6 +397,11 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
error = do_dup(td, DUP_VARIABLE, fd, newmin, td->td_retval); error = do_dup(td, DUP_VARIABLE, fd, newmin, td->td_retval);
break; break;
case F_DUP2FD:
tmp = arg;
error = do_dup(td, DUP_FIXED, fd, tmp, td->td_retval);
break;
case F_GETFD: case F_GETFD:
FILEDESC_SLOCK(fdp); FILEDESC_SLOCK(fdp);
if ((fp = fdtofp(fd, fdp)) == NULL) { if ((fp = fdtofp(fd, fdp)) == NULL) {
@ -633,7 +638,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg)
} }
/* /*
* Common code for dup, dup2, and fcntl(F_DUPFD). * Common code for dup, dup2, fcntl(F_DUPFD) and fcntl(F_DUP2FD).
*/ */
static int static int
do_dup(struct thread *td, enum dup_type type, int old, int new, do_dup(struct thread *td, enum dup_type type, int old, int new,

View File

@ -181,6 +181,7 @@ typedef __pid_t pid_t;
#define F_GETLK 7 /* get record locking information */ #define F_GETLK 7 /* get record locking information */
#define F_SETLK 8 /* set record locking information */ #define F_SETLK 8 /* set record locking information */
#define F_SETLKW 9 /* F_SETLK; wait if blocked */ #define F_SETLKW 9 /* F_SETLK; wait if blocked */
#define F_DUP2FD 10 /* duplicate file descriptor to arg */
/* file descriptor flags (F_GETFD, F_SETFD) */ /* file descriptor flags (F_GETFD, F_SETFD) */
#define FD_CLOEXEC 1 /* close-on-exec flag */ #define FD_CLOEXEC 1 /* close-on-exec flag */

View File

@ -20,6 +20,15 @@
* Test #9: check if fcntl(F_DUPFD) cleared close-on-exec flag for duped fd. * Test #9: check if fcntl(F_DUPFD) cleared close-on-exec flag for duped fd.
* Test #10: check if dup2() to a fd > current maximum number of open files * Test #10: check if dup2() to a fd > current maximum number of open files
* limit work. * limit work.
* Test #11: check if fcntl(F_DUP2FD) works.
* Test #12: check if fcntl(F_DUP2FD) returned a fd we asked for.
* Test #13: check if fcntl(F_DUP2FD) cleared close-on-exec flag for duped fd.
* Test #14: check if fcntl(F_DUP2FD) allows to dup fd to itself.
* Test #15: check if fcntl(F_DUP2FD) returned a fd we asked for.
* Test #16: check if fcntl(F_DUP2FD) did not clear close-on-exec flag for
* duped fd.
* Test #17: check if fcntl(F_DUP2FD) to a fd > current maximum number of open
* files limit work.
*/ */
#include <sys/types.h> #include <sys/types.h>
@ -56,7 +65,7 @@ main(int __unused argc, char __unused *argv[])
orgfd = getafile(); orgfd = getafile();
printf("1..10\n"); printf("1..17\n");
/* If dup(2) ever work? */ /* If dup(2) ever work? */
if ((fd1 = dup(orgfd)) < 0) if ((fd1 = dup(orgfd)) < 0)
@ -151,10 +160,70 @@ main(int __unused argc, char __unused *argv[])
++test; ++test;
if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
err(1, "getrlimit"); err(1, "getrlimit");
if ((fd2 = dup2(fd1, rlp.rlim_cur + 1)) == 0) if ((fd2 = dup2(fd1, rlp.rlim_cur + 1)) >= 0)
printf("not ok %d - dup2(2) bypassed NOFILE limit\n", test); printf("not ok %d - dup2(2) bypassed NOFILE limit\n", test);
else else
printf("ok %d - dup2(2) didn't bypass NOFILE limit\n", test); printf("ok %d - dup2(2) didn't bypass NOFILE limit\n", test);
/* If fcntl(F_DUP2FD) ever work? */
if ((fd2 = fcntl(fd1, F_DUP2FD, fd1 + 1)) < 0)
err(1, "fcntl(F_DUP2FD)");
printf("ok %d - fcntl(F_DUP2FD) works\n", ++test);
/* Do we get the right fd? */
++test;
if (fd2 != fd1 + 1)
printf(
"no ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n",
test);
else
printf("ok %d - fcntl(F_DUP2FD) returned a correct fd\n",
test);
/* Was close-on-exec cleared? */
++test;
if (fcntl(fd2, F_GETFD) != 0)
printf(
"not ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n",
test);
else
printf("ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n",
test);
/* Dup to itself */
if ((fd2 = fcntl(fd1, F_DUP2FD, fd1)) < 0)
err(1, "fcntl(F_DUP2FD)");
printf("ok %d - fcntl(F_DUP2FD) to itself works\n", ++test);
/* Do we get the right fd? */
++test;
if (fd2 != fd1)
printf(
"not ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n",
test);
else
printf(
"ok %d - fcntl(F_DUP2FD) to itself returned a correct fd\n",
test);
/* Was close-on-exec cleared? */
++test;
if (fcntl(fd2, F_GETFD) == 0)
printf("not ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n",
test);
else
printf("ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n",
test);
++test;
if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
err(1, "getrlimit");
if ((fd2 = fcntl(fd1, F_DUP2FD, rlp.rlim_cur + 1)) >= 0)
printf("not ok %d - fcntl(F_DUP2FD) bypassed NOFILE limit\n",
test);
else
printf("ok %d - fcntl(F_DUP2FD) didn't bypass NOFILE limit\n",
test);
return (0); return (0);
} }