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:
parent
40f9a23605
commit
e3ad7f6626
@ -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 .
|
||||||
|
@ -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,
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user