kern/120233: FreeBSD is missing fcntl() operation F_DUP2FD

Jukka Ukkonen jau at iki.fi
Sat Feb 2 23:20:01 PST 2008


>Number:         120233
>Category:       kern
>Synopsis:       FreeBSD is missing fcntl() operation F_DUP2FD
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Feb 03 07:20:00 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Jukka Ukkonen
>Release:        FreeBSD 6.3-STABLE
>Organization:
private person
>Environment:
FreeBSD mjolnir 6.3-STABLE FreeBSD 6.3-STABLE #0: Sat Feb  2 12:48:48 EET 2008     root at mjolnir:/usr/obj/usr/src/sys/Mjolnir  i386
>Description:
This is a compatibility issue.

At least SunOS/Solaris and AIX both have an fcntl() operation F_DUP2FD which is
to dup2() as F_DUPFD is to dup().
Having support to this fcntl() operation would improve software portability
between FreeBSD and other UNIX style systems.
Additionally it would allow both dup() and dup2() be implemented as library
functions narrowing down the system call API.

This PR supersedes the 3.5 years old kern/70798 which provided the same feature
for FreeBSD-4.10. The old ticket is still in the state open and nobody has
cared as much as to say a simple "no" since its introduction.

This PR contains an upgraded patch against FreeBSD-6.3 sources implementing
the F_DUP2FD operation and a test program to show F_DUP2FD in action,
if it is supported.

I have had this modification in my own environments for some 4 years starting
from FreeBSD-4.x with no ill effects.
In fact in my own C library I have both dup() and dup2() only as wrappers for
fcntl() and everything works just fine.

>How-To-Repeat:
Try the test program shown below before and after applying the patch and notice
the difference in its output.


#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

static void
dumpstat (st)
    struct stat	*st;
{
    printf ("st_dev   = %ld\n", (long) st->st_dev);
    printf ("st_ino   = %ld\n", (long) st->st_ino);
    printf ("st_nlink = %ld\n", (long) st->st_nlink);
    printf ("st_uid   = %ld\n", (long) st->st_uid);
    printf ("st_gid   = %ld\n", (long) st->st_gid);
    printf ("st_rdev  = %ld\n", (long) st->st_rdev);
}

static void
viewfdstat (fd)
    int	    fd;
{
    struct stat	st1;

    if (fstat (fd, &st1) < 0) {
	fprintf (stderr, "fstat(%d): %s\n", fd, strerror (errno));
    }
    else {
	printf ("fstat(%d):\n", fd);

	dumpstat (&st1);
    }
}

int
main (ac, av)
    int	    ac;
    char    *av[];
{
    int	    fd;

    viewfdstat (0);

    fd = open ("/dev/null", O_RDWR, 0);

    viewfdstat (fd);

#ifndef	F_DUP2FD
#define F_DUP2FD    F_DUPFD
#warning This system does not support F_DUP2FD.
#endif

    if (fcntl (fd, F_DUP2FD, 0) < 0) {
	fprintf (stderr,
		 "fcntl(%d, F_DUP2FD, 0): %s\n",
		 fd, strerror (errno));
    }

    viewfdstat (0);

    return (0);
}


>Fix:
Apply the attached patch.


Patch attached with submission follows:

--- sys/sys/fcntl.h.orig	2008-02-02 07:45:25.000000000 +0200
+++ sys/sys/fcntl.h	2008-02-02 07:47:21.000000000 +0200
@@ -176,6 +176,7 @@
 #define	F_GETLK		7		/* get record locking information */
 #define	F_SETLK		8		/* set record locking information */
 #define	F_SETLKW	9		/* F_SETLK; wait if blocked */
+#define	F_DUP2FD	10		/* duplicate file descriptor, fixed */
 
 /* file descriptor flags (F_GETFD, F_SETFD) */
 #define	FD_CLOEXEC	1		/* close-on-exec flag */
--- sys/kern/kern_descrip.c.orig	2008-02-02 07:39:50.000000000 +0200
+++ sys/kern/kern_descrip.c	2008-02-02 07:41:31.000000000 +0200
@@ -365,6 +365,7 @@
 	 */
 	switch (cmd) {
 	case F_DUPFD:
+	case F_DUP2FD:
 	case F_GETFD:
 	case F_SETFD:
 	case F_GETFL:
@@ -405,6 +406,21 @@
 		error = do_dup(td, DUP_VARIABLE, fd, newmin, td->td_retval);
 		break;
 
+	case F_DUP2FD:
+		/* mtx_assert(&Giant, MA_NOTOWNED); */
+		FILEDESC_UNLOCK(fdp);
+		newmin = arg;
+		PROC_LOCK(p);
+		if (newmin >= lim_cur(p, RLIMIT_NOFILE) ||
+		    newmin >= maxfilesperproc) {
+			PROC_UNLOCK(p);
+			error = EINVAL;
+			break;
+		}
+		PROC_UNLOCK(p);
+		error = do_dup(td, DUP_FIXED, fd, newmin, td->td_retval);
+		break;
+
 	case F_GETFD:
 		/* mtx_assert(&Giant, MA_NOTOWNED); */
 		td->td_retval[0] = (*pop & UF_EXCLOSE) ? FD_CLOEXEC : 0;


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list