kernel: Add three new commands to fctnl
authorJohn Marino <draco@marino.st>
Wed, 12 Jun 2013 19:42:21 +0000 (21:42 +0200)
committerJohn Marino <draco@marino.st>
Wed, 12 Jun 2013 23:20:45 +0000 (01:20 +0200)
This commit adds the following new commands to fcntl():
  F_DUP2FD         - non-portable functional equivalent of dup2(fd, arg)
  F_DUPFD_CLOEXEC  - A version of F_DUPFD that sets the close-on-exec
                     on the new file descriptor
  F_DUP2FD_CLOEXEC - A version of F_DUP2FD that sets the close-on-exec
                     on the new file descriptor.  It is non-portable

It also adds a missing break in a case statement for F_GETOWN in
sys_fnctl(), spotted by dillon.

reviewed-by: dillon

lib/libc/sys/fcntl.2
sys/kern/kern_descrip.c
sys/sys/fcntl.h
sys/sys/kern_syscall.h

index 952cfac..ece6c57 100644 (file)
@@ -28,7 +28,7 @@
 .\"     @(#)fcntl.2    8.2 (Berkeley) 1/12/94
 .\" $FreeBSD: src/lib/libc/sys/fcntl.2,v 1.16.2.13 2002/07/22 15:15:16 bde Exp $
 .\"
-.Dd January 12, 1994
+.Dd June 12, 2013
 .Dt FCNTL 2
 .Os
 .Sh NAME
 .Ft int
 .Fn fcntl "int fd" "int cmd" "..."
 .Sh DESCRIPTION
-.Fn Fcntl
-provides for control over descriptors.
+The
+.Fn fcntl
+system call provides for control over descriptors.
 The argument
 .Fa fd
 is a descriptor to be operated on by
 .Fa cmd
-as described below.  Depending on the value of
+as described below.
+Depending on the value of
 .Fa cmd ,
-.Nm
+.Fn fcntl
 can take an additional third argument
 .Fa "int arg" .
-.Bl -tag -width F_GETOWNX
+.Bl -tag -width F_DUP2FD_CLOEXEC
 .It Dv F_DUPFD
 Return a new descriptor as follows:
 .Pp
@@ -71,11 +73,44 @@ Same access mode (read, write or read/write).
 Same file status flags (i.e., both file descriptors
 share the same file status flags).
 .It
-The close-on-exec flag associated with the new file descriptor
-is set to remain open across
+The close-on-exec flag
+.Dv FD_CLOEXEC
+associated with the new file descriptor is cleared, so the file descriptor is
+to remain open across
 .Xr execve 2
 system calls.
 .El
+.It Dv F_DUPFD_CLOEXEC
+Like
+.Dv F_DUPFD ,
+but the
+.Dv FD_CLOEXEC
+flag associated with the new file descriptor is set, so the file descriptor
+is closed when
+.Xr execve 2
+system call executes.
+.It Dv F_DUP2FD
+It is functionally equivalent to
+.Bd -literal -offset indent
+dup2(fd, arg)
+.Ed
+.It Dv F_DUP2FD_CLOEXEC
+Like
+.Dv F_DUP2FD ,
+but the
+.Dv FD_CLOEXEC
+flag associated with the new file descriptor is set.
+.Pp
+The
+.Dv F_DUP2FD
+and
+.Dv F_DUP2FD_CLOEXEC
+constants are not portable, so they should not be used if
+portability is needed.
+Use
+.Fn dup2
+instead of
+.Dv F_DUP2FD .
 .It Dv F_GETFD
 Get the close-on-exec flag associated with the file descriptor
 .Fa fd
@@ -140,7 +175,7 @@ flags are as follows:
 .It Dv O_NONBLOCK
 Non-blocking I/O; if no data is available to a
 .Xr read 2
-call, or if a
+system call, or if a
 .Xr write 2
 operation would block,
 the read or write call returns -1 with the error
@@ -152,8 +187,10 @@ corresponds to the
 flag of
 .Xr open 2 .
 .It Dv O_DIRECT
-Minimize or eliminate the cache effects of reading and writing.  The system
-will attempt to avoid caching the data you read or write.  If it cannot
+Minimize or eliminate the cache effects of reading and writing.
+The system
+will attempt to avoid caching the data you read or write.
+If it cannot
 avoid caching the data, it will minimize the impact the data has on the cache.
 Use of this flag can drastically reduce performance if not used with care.
 .It Dv O_ASYNC
@@ -190,7 +227,7 @@ in the
 .Fa flock
 structure.
 If no lock is found that would prevent this lock from being created,
-the structure is left unchanged by this function call except for the
+the structure is left unchanged by this system call except for the
 lock type which is set to
 .Dv F_UNLCK .
 .It Dv F_SETLK
@@ -324,20 +361,36 @@ requested a lock on the database.
 Another minor semantic problem with this interface is that
 locks are not inherited by a child process created using the
 .Xr fork 2
-function.
+system call.
 The
 .Xr flock 2
 interface has much more rational last close semantics and
 allows locks to be inherited by child processes.
-.Xr Flock 2
-is recommended for applications that want to ensure the integrity
+The
+.Xr flock 2
+system call is recommended for applications that want to ensure the integrity
 of their locks when using library routines or wish to pass locks
 to their children.
-Note that
-.Xr flock 2
+.Pp
+The
+.Fn fcntl ,
+.Xr flock 2 ,
 and
-.Xr fcntl 2
-locks may be safely used concurrently but
+.Xr lockf 3
+locks are compatible.
+Processes using different locking interfaces can cooperate
+over the same file safely.
+However, only one of such interfaces should be used within
+the same process.
+If a file is locked by a process through
+.Xr flock 2 ,
+any record within the file will be seen as locked
+from the viewpoint of another process using
+.Fn fcntl
+or
+.Xr lockf 3 ,
+and vice versa.
+Note that
 .Fn fcntl F_GETLK
 returns \-1 in
 .Fa l_pid
@@ -367,6 +420,9 @@ as follows:
 .Bl -tag -width F_GETOWNX -offset indent
 .It Dv F_DUPFD
 A new file descriptor.
+.It Dv F_DUP2FD
+A file descriptor equal to
+.Fa arg .
 .It Dv F_GETFD
 Value of flag (only the low-order bit is defined).
 .It Dv F_GETFL
@@ -381,8 +437,9 @@ Otherwise, a value of -1 is returned and
 .Va errno
 is set to indicate the error.
 .Sh ERRORS
-.Fn Fcntl
-will fail if:
+The
+.Fn fcntl
+system call will fail if:
 .Bl -tag -width Er
 .It Bq Er EAGAIN
 The argument
@@ -401,12 +458,22 @@ or the type is an exclusive lock and some portion of the
 segment of a file to be locked is already shared-locked or
 exclusive-locked by another process.
 .It Bq Er EBADF
-.Fa \&Fd
+The
+.Fa fd
+argument
 is not a valid open file descriptor.
 .Pp
 The argument
 .Fa cmd
 is
+.Dv F_DUP2FD ,
+and
+.Fa arg
+is not a valid file descriptor.
+.Pp
+The argument
+.Fa cmd
+is
 .Dv F_SETLK
 or
 .Dv F_SETLKW ,
@@ -442,9 +509,11 @@ The argument
 .Fa cmd
 is
 .Dv F_SETLKW ,
-and the function was interrupted by a signal.
+and the system call was interrupted by a signal.
 .It Bq Er EINVAL
-.Fa Cmd
+The
+.Fa cmd
+argument
 is
 .Dv F_DUPFD
 and
@@ -457,14 +526,12 @@ The argument
 .Fa cmd
 is
 .Dv F_GETLK ,
-.Dv F_SETLK ,
+.Dv F_SETLK
 or
 .Dv F_SETLKW
 and the data to which
 .Fa arg
-points is not valid, or
-.Fa fd
-refers to a file that does not support locking.
+points is not valid.
 .It Bq Er EMFILE
 The argument
 .Fa cmd
@@ -485,14 +552,18 @@ or
 and satisfying the lock or unlock request would result in the
 number of locked regions in the system exceeding a system-imposed limit.
 .It Bq Er EPERM
-.Fa Cmd
+The
+.Fa cmd
+argument
 is
 .Dv F_SETOWN
 and
 the process ID or process group given as an argument is in a
 different session than the caller.
 .It Bq Er ESRCH
-.Fa Cmd
+The
+.Fa cmd
+argument
 is
 .Dv F_SETOWN
 and
@@ -516,15 +587,30 @@ for the reasons as stated in
 .Xr tcgetpgrp 3 .
 .Sh SEE ALSO
 .Xr close 2 ,
+.Xr dup2 2 ,
 .Xr execve 2 ,
 .Xr flock 2 ,
 .Xr getdtablesize 2 ,
 .Xr open 2 ,
 .Xr sigaction 2 ,
+.Xr lockf 3 ,
 .Xr tcgetpgrp 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
 The
 .Fn fcntl
-function call appeared in
+system call appeared in
 .Bx 4.2 .
+.Pp
+The
+.Dv F_DUP_CLOEXEC ,
+.Dv F_DUP2FD
+and
+.Dv F_DUP2FD_CLOEXEC
+constants first appeared in
+.Dx 3.5 .
index 670be78..831f244 100644 (file)
@@ -253,6 +253,20 @@ kern_fcntl(int fd, int cmd, union fcntl_dat *dat, struct ucred *cred)
                newmin = dat->fc_fd;
                error = kern_dup(DUP_VARIABLE, fd, newmin, &dat->fc_fd);
                return (error);
+       case F_DUP2FD:
+               newmin = dat->fc_fd;
+               error = kern_dup(DUP_FIXED, fd, newmin, &dat->fc_fd);
+               return (error);
+       case F_DUPFD_CLOEXEC:
+               newmin = dat->fc_fd;
+               error = kern_dup(DUP_VARIABLE | DUP_CLOEXEC, fd, newmin,
+                                &dat->fc_fd);
+               return (error);
+       case F_DUP2FD_CLOEXEC:
+               newmin = dat->fc_fd;
+               error = kern_dup(DUP_FIXED | DUP_CLOEXEC, fd, newmin,
+                                &dat->fc_fd);
+               return (error);
        default:
                break;
        }
@@ -406,6 +420,9 @@ sys_fcntl(struct fcntl_args *uap)
 
        switch (uap->cmd) {
        case F_DUPFD:
+       case F_DUP2FD:
+       case F_DUPFD_CLOEXEC:
+       case F_DUP2FD_CLOEXEC:
                dat.fc_fd = uap->arg;
                break;
        case F_SETFD:
@@ -432,6 +449,9 @@ sys_fcntl(struct fcntl_args *uap)
        if (error == 0) {
                switch (uap->cmd) {
                case F_DUPFD:
+               case F_DUP2FD:
+               case F_DUPFD_CLOEXEC:
+               case F_DUP2FD_CLOEXEC:
                        uap->sysmsg_result = dat.fc_fd;
                        break;
                case F_GETFD:
@@ -442,6 +462,7 @@ sys_fcntl(struct fcntl_args *uap)
                        break;
                case F_GETOWN:
                        uap->sysmsg_result = dat.fc_owner;
+                       break;
                case F_GETLK:
                        error = copyout(&dat.fc_flock, (caddr_t)uap->arg,
                            sizeof(struct flock));
@@ -455,15 +476,18 @@ sys_fcntl(struct fcntl_args *uap)
 /*
  * Common code for dup, dup2, and fcntl(F_DUPFD).
  *
- * The type flag can be either DUP_FIXED or DUP_VARIABLE.  DUP_FIXED tells
- * kern_dup() to destructively dup over an existing file descriptor if new
- * is already open.  DUP_VARIABLE tells kern_dup() to find the lowest
- * unused file descriptor that is greater than or equal to new.
+ * There are three type flags: DUP_FIXED, DUP_VARIABLE, and DUP_CLOEXEC.
+ * The first two flags are mutually exclusive, and the third is optional.
+ * DUP_FIXED tells kern_dup() to destructively dup over an existing file
+ * descriptor if "new" is already open.  DUP_VARIABLE tells kern_dup()
+ * to find the lowest unused file descriptor that is greater than or
+ * equal to "new".  DUP_CLOEXEC, which works with either of the first
+ * two flags, sets the close-on-exec flag on the "new" file descriptor.
  *
  * MPSAFE
  */
 int
-kern_dup(enum dup_type type, int old, int new, int *res)
+kern_dup(int flags, int old, int new, int *res)
 {
        struct thread *td = curthread;
        struct proc *p = td->td_proc;
@@ -499,8 +523,10 @@ retry:
                spin_unlock(&fdp->fd_spin);
                return (EBADF);
        }
-       if (type == DUP_FIXED && old == new) {
+       if ((flags & DUP_FIXED) && old == new) {
                *res = new;
+               if (flags & DUP_CLOEXEC)
+                       fdp->fd_files[new].fileflags |= UF_EXCLOSE;
                spin_unlock(&fdp->fd_spin);
                return (0);
        }
@@ -519,7 +545,7 @@ retry:
         * the target descriptor to a reserved state so we have a uniform
         * setup for the next code block.
         */
-       if (type == DUP_VARIABLE || new >= fdp->fd_nfiles) {
+       if ((flags & DUP_VARIABLE) || new >= fdp->fd_nfiles) {
                spin_unlock(&fdp->fd_spin);
                error = fdalloc(p, new, &newfd);
                spin_lock(&fdp->fd_spin);
@@ -540,7 +566,7 @@ retry:
                /*
                 * Check for expansion race
                 */
-               if (type != DUP_VARIABLE && new != newfd) {
+               if ((flags & DUP_VARIABLE) == 0 && new != newfd) {
                        fsetfd_locked(fdp, NULL, newfd);
                        spin_unlock(&fdp->fd_spin);
                        fdrop(fp);
@@ -599,7 +625,7 @@ retry:
        } else {
                holdleaders = 0;
        }
-       KASSERT(delfp == NULL || type == DUP_FIXED,
+       KASSERT(delfp == NULL || (flags & DUP_FIXED),
                ("dup() picked an open file"));
 
        /*
@@ -610,7 +636,10 @@ retry:
         * The fd_files[] array inherits fp's hold reference.
         */
        fsetfd_locked(fdp, fp, new);
-       fdp->fd_files[new].fileflags = oldflags & ~UF_EXCLOSE;
+       if ((flags & DUP_CLOEXEC) != 0)
+               fdp->fd_files[new].fileflags = oldflags | UF_EXCLOSE;
+       else
+               fdp->fd_files[new].fileflags = oldflags & ~UF_EXCLOSE;
        spin_unlock(&fdp->fd_spin);
        fdrop(fp);
        *res = new;
index 00fab35..3515989 100644 (file)
 #define        F_SETFL         4               /* set file status flags */
 #ifndef _POSIX_SOURCE
 #define        F_GETOWN        5               /* get SIGIO/SIGURG proc/pgrp */
-#define F_SETOWN       6               /* set SIGIO/SIGURG proc/pgrp */
+#define        F_SETOWN        6               /* set SIGIO/SIGURG proc/pgrp */
 #endif
 #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 to arg */
+#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809
+#define        F_DUPFD_CLOEXEC 17              /* Like F_DUPFD with FD_CLOEXEC set */
+#endif
+#if __BSD_VISIBLE
+#define        F_DUP2FD_CLOEXEC 18             /* Like F_DUP2FD with FD_CLOEXEC set */
+#endif
 
 /* file descriptor flags (F_GETFD, F_SETFD) */
 #define        FD_CLOEXEC      1               /* close-on-exec flag */
index 6e3cacf..bd49dbc 100644 (file)
@@ -37,7 +37,9 @@
 
 #include <sys/uio.h>
 
-enum dup_type {DUP_FIXED, DUP_VARIABLE};
+#define DUP_FIXED      0x1     /* Copy to specific fd even if in use */
+#define DUP_VARIABLE   0x2     /* Copy fd to an unused fd */
+#define DUP_CLOEXEC    0x4     /* Set fd close on exec flag */
 union fcntl_dat;
 struct image_args;
 struct plimit;
@@ -69,7 +71,7 @@ struct statvfs;
 /*
  * Prototypes for syscalls in kern/kern_descrip.c
  */
-int kern_dup(enum dup_type type, int old, int new, int *res);
+int kern_dup(int flags, int old, int new, int *res);
 int kern_fcntl(int fd, int cmd, union fcntl_dat *dat, struct ucred *cred);
 int kern_fstat(int fd, struct stat *st);