The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/kern_descrip.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
   29 /*
   30  * Copyright (c) 1982, 1986, 1989, 1991, 1993
   31  *      The Regents of the University of California.  All rights reserved.
   32  * (c) UNIX System Laboratories, Inc.
   33  * All or some portions of this file are derived from material licensed
   34  * to the University of California by American Telephone and Telegraph
   35  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   36  * the permission of UNIX System Laboratories, Inc.
   37  *
   38  * Redistribution and use in source and binary forms, with or without
   39  * modification, are permitted provided that the following conditions
   40  * are met:
   41  * 1. Redistributions of source code must retain the above copyright
   42  *    notice, this list of conditions and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  * 3. All advertising materials mentioning features or use of this software
   47  *    must display the following acknowledgement:
   48  *      This product includes software developed by the University of
   49  *      California, Berkeley and its contributors.
   50  * 4. Neither the name of the University nor the names of its contributors
   51  *    may be used to endorse or promote products derived from this software
   52  *    without specific prior written permission.
   53  *
   54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   64  * SUCH DAMAGE.
   65  *
   66  *      @(#)kern_descrip.c      8.8 (Berkeley) 2/14/95
   67  */
   68 /*
   69  * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
   70  * support for mandatory and extensible security protections.  This notice
   71  * is included in support of clause 2.2 (b) of the Apple Public License,
   72  * Version 2.0.
   73  */
   74 
   75 #include <sys/param.h>
   76 #include <sys/systm.h>
   77 #include <sys/filedesc.h>
   78 #include <sys/kernel.h>
   79 #include <sys/vnode_internal.h>
   80 #include <sys/proc_internal.h>
   81 #include <sys/kauth.h>
   82 #include <sys/file_internal.h>
   83 #include <sys/socket.h>
   84 #include <sys/socketvar.h>
   85 #include <sys/stat.h>
   86 #include <sys/ioctl.h>
   87 #include <sys/fcntl.h>
   88 #include <sys/malloc.h>
   89 #include <sys/mman.h>
   90 #include <sys/syslog.h>
   91 #include <sys/unistd.h>
   92 #include <sys/resourcevar.h>
   93 #include <sys/aio_kern.h>
   94 #include <sys/ev.h>
   95 #include <kern/lock.h>
   96 
   97 #include <bsm/audit_kernel.h>
   98 
   99 #include <sys/mount_internal.h>
  100 #include <sys/kdebug.h>
  101 #include <sys/sysproto.h>
  102 #include <sys/pipe.h>
  103 #include <kern/kern_types.h>
  104 #include <kern/kalloc.h>
  105 #include <libkern/OSAtomic.h>
  106 
  107 #include <sys/ubc.h>
  108 
  109 struct psemnode;
  110 struct pshmnode;
  111 
  112 int fdopen(dev_t dev, int mode, int type, proc_t p);
  113 int finishdup(proc_t p, struct filedesc *fdp, int old, int new, register_t *retval);
  114 
  115 int falloc_locked(proc_t p, struct fileproc **resultfp, int *resultfd, vfs_context_t ctx, int locked);
  116 int fdgetf_noref(proc_t p, int fd, struct fileproc **resultfp);
  117 void fg_drop(struct fileproc * fp);
  118 void fg_free(struct fileglob *fg);
  119 void fg_ref(struct fileproc * fp);
  120 
  121 /* flags for close_internal_locked */
  122 #define FD_DUP2RESV 1
  123 static int close_internal_locked(struct proc *p, int fd, struct fileproc *fp, int flags);
  124 
  125 static int closef_finish(struct fileproc *fp, struct fileglob *fg, proc_t p, vfs_context_t ctx);
  126 
  127 /* We don't want these exported */
  128 __private_extern__
  129 int open1(vfs_context_t, struct nameidata *, int, struct vnode_attr *, register_t *);
  130 
  131 __private_extern__
  132 int unlink1(vfs_context_t, struct nameidata *, int);
  133 
  134 static void _fdrelse(struct proc * p, int fd);
  135 
  136 
  137 extern void file_lock_init(void) __attribute__((section("__TEXT, initcode")));
  138 extern int kqueue_stat(struct fileproc *fp, void *ub, int isstat4, proc_t p);
  139 #if SOCKETS
  140 extern int soo_stat(struct socket *so, void *ub, int isstat64);
  141 #endif /* SOCKETS */
  142 
  143 extern kauth_scope_t    kauth_scope_fileop;
  144 
  145 #define f_flag f_fglob->fg_flag
  146 #define f_type f_fglob->fg_type
  147 #define f_msgcount f_fglob->fg_msgcount
  148 #define f_cred f_fglob->fg_cred
  149 #define f_ops f_fglob->fg_ops
  150 #define f_offset f_fglob->fg_offset
  151 #define f_data f_fglob->fg_data
  152 /*
  153  * Descriptor management.
  154  */
  155 struct filelist filehead;       /* head of list of open files */
  156 struct fmsglist fmsghead;       /* head of list of open files */
  157 struct fmsglist fmsg_ithead;    /* head of list of open files */
  158 int nfiles;                     /* actual number of open files */
  159 
  160 
  161 lck_grp_attr_t * file_lck_grp_attr;
  162 lck_grp_t * file_lck_grp;
  163 lck_attr_t * file_lck_attr;
  164 
  165 lck_mtx_t * uipc_lock;
  166 lck_mtx_t * file_flist_lock;
  167 
  168 
  169 /*
  170  * file_lock_init
  171  *
  172  * Description: Initialize the file lock group and the uipc and flist locks
  173  *
  174  * Parameters:  (void)
  175  *
  176  * Returns:     void
  177  *
  178  * Notes:       Called at system startup from bsd_init().
  179  */
  180 void
  181 file_lock_init(void)
  182 {
  183         /* allocate file lock group attribute and group */
  184         file_lck_grp_attr= lck_grp_attr_alloc_init();
  185 
  186         file_lck_grp = lck_grp_alloc_init("file",  file_lck_grp_attr);
  187 
  188         /* Allocate file lock attribute */
  189         file_lck_attr = lck_attr_alloc_init();
  190 
  191         uipc_lock = lck_mtx_alloc_init(file_lck_grp, file_lck_attr);
  192         file_flist_lock = lck_mtx_alloc_init(file_lck_grp, file_lck_attr);
  193 }
  194 
  195 
  196 /*
  197  * proc_fdlock, proc_fdlock_spin
  198  *
  199  * Description: Lock to control access to the per process struct fileproc
  200  *              and struct filedesc
  201  *
  202  * Parameters:  p                               Process to take the lock on
  203  *
  204  * Returns:     void
  205  *
  206  * Notes:       The lock is initialized in forkproc() and destroyed in
  207  *              reap_child_process().
  208  */
  209 void
  210 proc_fdlock(proc_t p)
  211 {
  212         lck_mtx_lock(&p->p_fdmlock);
  213 }
  214 
  215 void
  216 proc_fdlock_spin(proc_t p)
  217 {
  218         lck_mtx_lock_spin(&p->p_fdmlock);
  219 }
  220 
  221 void
  222 proc_fdlock_assert(proc_t p, int assertflags)
  223 {
  224         lck_mtx_assert(&p->p_fdmlock, assertflags);
  225 }
  226 
  227 
  228 /*
  229  * proc_fdunlock
  230  *
  231  * Description: Unlock the lock previously locked by a call to proc_fdlock()
  232  *
  233  * Parameters:  p                               Process to drop the lock on
  234  *
  235  * Returns:     void
  236  */
  237 void
  238 proc_fdunlock(proc_t p)
  239 {
  240         lck_mtx_unlock(&p->p_fdmlock);
  241 }
  242 
  243 
  244 /*
  245  * System calls on descriptors.
  246  */
  247 
  248 
  249 /*
  250  * getdtablesize
  251  *
  252  * Description: Returns the per process maximum size of the descriptor table
  253  *
  254  * Parameters:  p                               Process being queried
  255  *              retval                          Pointer to the call return area
  256  *
  257  * Returns:     0                               Success
  258  *
  259  * Implicit returns:
  260  *              *retval (modified)              Size of dtable
  261  */
  262 int
  263 getdtablesize(proc_t p, __unused struct getdtablesize_args *uap, register_t *retval)
  264 {
  265         proc_fdlock_spin(p);
  266         *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
  267         proc_fdunlock(p);
  268 
  269         return (0);
  270 }
  271 
  272 
  273 void
  274 procfdtbl_reservefd(struct proc * p, int fd)
  275 {
  276         p->p_fd->fd_ofiles[fd] = NULL;
  277         p->p_fd->fd_ofileflags[fd] |= UF_RESERVED;
  278 }
  279 
  280 void
  281 procfdtbl_markclosefd(struct proc * p, int fd)
  282 {
  283         p->p_fd->fd_ofileflags[fd] |= (UF_RESERVED | UF_CLOSING);
  284 }
  285 
  286 void
  287 procfdtbl_releasefd(struct proc * p, int fd, struct fileproc * fp)
  288 {
  289         if (fp != NULL)
  290                 p->p_fd->fd_ofiles[fd] = fp;
  291         p->p_fd->fd_ofileflags[fd] &= ~UF_RESERVED;
  292         if ((p->p_fd->fd_ofileflags[fd] & UF_RESVWAIT) == UF_RESVWAIT) {
  293                 p->p_fd->fd_ofileflags[fd] &= ~UF_RESVWAIT;
  294                 wakeup(&p->p_fd);
  295         }
  296 }
  297 
  298 void 
  299 procfdtbl_waitfd(struct proc * p, int fd)
  300 {
  301         p->p_fd->fd_ofileflags[fd] |= UF_RESVWAIT;
  302         msleep(&p->p_fd, &p->p_fdmlock, PRIBIO, "ftbl_waitfd", NULL);
  303 }
  304 
  305 
  306 void
  307 procfdtbl_clearfd(struct proc * p, int fd)
  308 {
  309         int waiting;
  310 
  311         waiting = (p->p_fd->fd_ofileflags[fd] & UF_RESVWAIT);
  312         p->p_fd->fd_ofiles[fd] = NULL;       
  313         p->p_fd->fd_ofileflags[fd] = 0;
  314         if ( waiting == UF_RESVWAIT) {
  315                 wakeup(&p->p_fd);
  316         }
  317 }
  318 
  319 /*
  320  * _fdrelse
  321  *
  322  * Description: Inline utility function to free an fd in a filedesc
  323  *
  324  * Parameters:  fdp                             Pointer to filedesc fd lies in
  325  *              fd                              fd to free
  326  *              reserv                          fd should be reserved
  327  *
  328  * Returns:     void
  329  *
  330  * Locks:       Assumes proc_fdlock for process pointing to fdp is held by
  331  *              the caller
  332  */
  333 static void
  334 _fdrelse(struct proc * p, int fd)
  335 {
  336         struct filedesc *fdp = p->p_fd;
  337         int nfd = 0;
  338 
  339         if (fd < fdp->fd_freefile)
  340                 fdp->fd_freefile = fd;
  341 #if DIAGNOSTIC
  342         if (fd > fdp->fd_lastfile)
  343                 panic("fdrelse: fd_lastfile inconsistent");
  344 #endif
  345         procfdtbl_clearfd(p, fd);
  346 
  347         while ((nfd = fdp->fd_lastfile) > 0 &&
  348                         fdp->fd_ofiles[nfd] == NULL &&
  349                         !(fdp->fd_ofileflags[nfd] & UF_RESERVED))
  350                 fdp->fd_lastfile--;
  351 }
  352 
  353 
  354 /*
  355  * dup
  356  *
  357  * Description: Duplicate a file descriptor.
  358  *
  359  * Parameters:  p                               Process performing the dup
  360  *              uap->fd                         The fd to dup
  361  *              retval                          Pointer to the call return area
  362  *
  363  * Returns:     0                               Success
  364  *              !0                              Errno
  365  *
  366  * Implicit returns:
  367  *              *retval (modified)              The new descriptor
  368  */
  369 int
  370 dup(proc_t p, struct dup_args *uap, register_t *retval)
  371 {
  372         struct filedesc *fdp = p->p_fd;
  373         int old = uap->fd;
  374         int new, error;
  375         struct fileproc *fp;
  376 
  377         proc_fdlock(p);
  378         if ( (error = fp_lookup(p, old, &fp, 1)) ) {
  379                 proc_fdunlock(p);
  380                 return(error);
  381         }
  382         if ( (error = fdalloc(p, 0, &new)) ) {
  383                 fp_drop(p, old, fp, 1);
  384                 proc_fdunlock(p);
  385                 return (error);
  386         }
  387         error = finishdup(p, fdp, old, new, retval);
  388         fp_drop(p, old, fp, 1);
  389         proc_fdunlock(p);
  390 
  391         return (error);
  392 }
  393 
  394 
  395 /*
  396  * dup2
  397  *
  398  * Description: Duplicate a file descriptor to a particular value.
  399  *
  400  * Parameters:  p                               Process performing the dup
  401  *              uap->fd                         The fd to dup
  402  *              uap->to                         The fd to dup it to
  403  *              retval                          Pointer to the call return area
  404  *
  405  * Returns:     0                               Success
  406  *              !0                              Errno
  407  *
  408  * Implicit returns:
  409  *              *retval (modified)              The new descriptor
  410  */
  411 int
  412 dup2(proc_t p, struct dup2_args *uap, register_t *retval)
  413 {
  414         struct filedesc *fdp = p->p_fd;
  415         int old = uap->from, new = uap->to;
  416         int i, error;
  417         struct fileproc *fp, *nfp;
  418 
  419         proc_fdlock(p);
  420 
  421 startover:
  422         if ( (error = fp_lookup(p, old, &fp, 1)) ) {
  423                 proc_fdunlock(p);
  424                 return(error);
  425         }
  426         if (new < 0 ||
  427                 (rlim_t)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
  428             new >= maxfiles) {
  429                 fp_drop(p, old, fp, 1);
  430                 proc_fdunlock(p);
  431                 return (EBADF);
  432         }
  433         if (old == new) {
  434                 fp_drop(p, old, fp, 1);
  435                 *retval = new;
  436                 proc_fdunlock(p);
  437                 return (0);
  438         }
  439         if (new < 0 || new >= fdp->fd_nfiles) {
  440                 if ( (error = fdalloc(p, new, &i)) ) {
  441                         fp_drop(p, old, fp, 1);
  442                         proc_fdunlock(p);
  443                         return (error);
  444                 }
  445                 if (new != i) {
  446                         fdrelse(p, i);
  447                         goto closeit;
  448                 }
  449         } else {
  450 closeit:
  451                 while ((fdp->fd_ofileflags[new] & UF_RESERVED) == UF_RESERVED)  {
  452                                 fp_drop(p, old, fp, 1);
  453                                 procfdtbl_waitfd(p, new);
  454 #if DIAGNOSTIC
  455                                 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
  456 #endif
  457                                 goto startover;
  458                 }
  459 
  460                 if ((fdp->fd_ofiles[new] != NULL)  && ((error = fp_lookup(p, new, &nfp, 1)) == 0)) {
  461                         fp_drop(p, old, fp, 1);
  462                         (void)close_internal_locked(p, new, nfp, FD_DUP2RESV);
  463 #if DIAGNOSTIC
  464                         proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
  465 #endif
  466                         procfdtbl_clearfd(p, new);
  467                         goto startover;
  468                 } else  {
  469 #if DIAGNOSTIC
  470                         if (fdp->fd_ofiles[new] != NULL)
  471                                 panic("dup2: unable to get ref on a fileproc %d\n", new);
  472 #endif
  473                         procfdtbl_reservefd(p, new);
  474                 }
  475 
  476 #if DIAGNOSTIC
  477                 proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
  478 #endif
  479 
  480         }
  481 #if DIAGNOSTIC
  482         if (fdp->fd_ofiles[new] != 0)
  483                 panic("dup2-1: overwriting fd_ofiles with new %d\n", new);
  484         if ((fdp->fd_ofileflags[new] & UF_RESERVED) == 0)
  485                 panic("dup2-1: unreserved  fileflags  with new %d\n", new);
  486 #endif
  487         error = finishdup(p, fdp, old, new, retval);
  488         fp_drop(p, old, fp, 1);
  489         proc_fdunlock(p);
  490 
  491         return(error);
  492 }
  493 
  494 
  495 /*
  496  * fcntl
  497  *
  498  * Description: The file control system call.
  499  *
  500  * Parameters:  p                               Process performing the fcntl
  501  *              uap->fd                         The fd to operate against
  502  *              uap->cmd                        The command to perform
  503  *              uap->arg                        Pointer to the command argument
  504  *              retval                          Pointer to the call return area
  505  *
  506  * Returns:     0                               Success
  507  *              !0                              Errno (see fcntl_nocancel)
  508  *
  509  * Implicit returns:
  510  *              *retval (modified)              fcntl return value (if any)
  511  *
  512  * Notes:       This system call differs from fcntl_nocancel() in that it
  513  *              tests for cancellation prior to performing a potentially
  514  *              blocking operation.
  515  */
  516 int
  517 fcntl(proc_t p, struct fcntl_args *uap, register_t *retval)
  518 {
  519         __pthread_testcancel(1);
  520         return(fcntl_nocancel(p, (struct fcntl_nocancel_args *)uap, retval));
  521 }
  522 
  523 
  524 /*
  525  * fcntl_nocancel
  526  *
  527  * Description: A non-cancel-testing file control system call.
  528  *
  529  * Parameters:  p                               Process performing the fcntl
  530  *              uap->fd                         The fd to operate against
  531  *              uap->cmd                        The command to perform
  532  *              uap->arg                        Pointer to the command argument
  533  *              retval                          Pointer to the call return area
  534  *
  535  * Returns:     0                               Success
  536  *              EINVAL
  537  *      fp_lookup:EBADF                         Bad file descriptor
  538  * [F_DUPFD]
  539  *      fdalloc:EMFILE
  540  *      fdalloc:ENOMEM
  541  *      finishdup:EBADF
  542  *      finishdup:ENOMEM
  543  * [F_SETOWN]
  544  *              ESRCH
  545  * [F_SETLK]
  546  *              EBADF
  547  *              EOVERFLOW
  548  *      copyin:EFAULT
  549  *      vnode_getwithref:???
  550  *      VNOP_ADVLOCK:???
  551  * [F_GETLK]
  552  *              EBADF
  553  *              EOVERFLOW
  554  *      copyin:EFAULT
  555  *      copyout:EFAULT
  556  *      vnode_getwithref:???
  557  *      VNOP_ADVLOCK:???
  558  * [F_PREALLOCATE]
  559  *              EBADF
  560  *              EINVAL
  561  *      copyin:EFAULT
  562  *      copyout:EFAULT
  563  *      vnode_getwithref:???
  564  *      VNOP_ALLOCATE:???
  565  * [F_SETSIZE,F_RDADVISE]
  566  *              EBADF
  567  *      copyin:EFAULT
  568  *      vnode_getwithref:???
  569  * [F_RDAHEAD,F_NOCACHE]
  570  *              EBADF
  571  *      vnode_getwithref:???
  572  * [???]
  573  *
  574  * Implicit returns:
  575  *              *retval (modified)              fcntl return value (if any)
  576  */
  577 int
  578 fcntl_nocancel(proc_t p, struct fcntl_nocancel_args *uap, register_t *retval)
  579 {
  580         int fd = uap->fd;
  581         struct filedesc *fdp = p->p_fd;
  582         struct fileproc *fp;
  583         char *pop;
  584         struct vnode *vp = NULLVP;      /* for AUDIT_ARG() at end */
  585         int i, tmp, error, error2, flg = F_POSIX;
  586         struct flock fl;
  587         struct vfs_context context;
  588         off_t offset;
  589         int newmin;
  590         daddr64_t lbn, bn;
  591         int devBlockSize = 0;
  592         unsigned int fflag;
  593         user_addr_t argp;
  594 
  595         AUDIT_ARG(fd, uap->fd);
  596         AUDIT_ARG(cmd, uap->cmd);
  597 
  598         proc_fdlock(p);
  599         if ( (error = fp_lookup(p, fd, &fp, 1)) ) {
  600                 proc_fdunlock(p);
  601                 return(error);
  602         }
  603         context.vc_thread = current_thread();
  604         context.vc_ucred = fp->f_cred;
  605         if (proc_is64bit(p)) {
  606                 argp = uap->arg;
  607         }
  608         else {
  609                 /*
  610                  * Since the arg parameter is defined as a long but may be
  611                  * either a long or a pointer we must take care to handle
  612                  * sign extension issues.  Our sys call munger will sign
  613                  * extend a long when we are called from a 32-bit process.
  614                  * Since we can never have an address greater than 32-bits
  615                  * from a 32-bit process we lop off the top 32-bits to avoid
  616                  * getting the wrong address
  617                  */
  618                 argp = CAST_USER_ADDR_T(uap->arg);
  619         }
  620 
  621         pop = &fdp->fd_ofileflags[fd];
  622 
  623 #if CONFIG_MACF
  624         error = mac_file_check_fcntl(proc_ucred(p), fp->f_fglob, uap->cmd,
  625             uap->arg);
  626         if (error)
  627                 goto out;
  628 #endif
  629 
  630         switch (uap->cmd) {
  631 
  632         case F_DUPFD:
  633                 newmin = CAST_DOWN(int, uap->arg);
  634                 if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
  635                     newmin >= maxfiles) {
  636                         error = EINVAL;
  637                         goto out;
  638                 }
  639                 if ( (error = fdalloc(p, newmin, &i)) )
  640                         goto out;
  641                 error = finishdup(p, fdp, fd, i, retval);
  642                 goto out;
  643 
  644         case F_GETFD:
  645                 *retval = (*pop & UF_EXCLOSE)? 1 : 0;
  646                 error = 0;
  647                 goto out;
  648 
  649         case F_SETFD:
  650                 *pop = (*pop &~ UF_EXCLOSE) |
  651                         (uap->arg & 1)? UF_EXCLOSE : 0;
  652                 error = 0;
  653                 goto out;
  654 
  655         case F_GETFL:
  656                 *retval = OFLAGS(fp->f_flag);
  657                 error = 0;
  658                 goto out;
  659 
  660         case F_SETFL:
  661                 fp->f_flag &= ~FCNTLFLAGS;
  662                 tmp = CAST_DOWN(int, uap->arg);
  663                 fp->f_flag |= FFLAGS(tmp) & FCNTLFLAGS;
  664                 tmp = fp->f_flag & FNONBLOCK;
  665                 error = fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, &context);
  666                 if (error)
  667                         goto out;
  668                 tmp = fp->f_flag & FASYNC;
  669                 error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, &context);
  670                 if (!error)
  671                         goto out;
  672                 fp->f_flag &= ~FNONBLOCK;
  673                 tmp = 0;
  674                 (void)fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, &context);
  675                 goto out;
  676 
  677         case F_GETOWN:
  678                 if (fp->f_type == DTYPE_SOCKET) {
  679                         *retval = ((struct socket *)fp->f_data)->so_pgid;
  680                         error = 0;
  681                         goto out;
  682                 }
  683                 error = fo_ioctl(fp, (int)TIOCGPGRP, (caddr_t)retval, &context);
  684                 *retval = -*retval;
  685                 goto out;
  686 
  687         case F_SETOWN:
  688                 tmp = CAST_DOWN(pid_t, uap->arg);
  689                 if (fp->f_type == DTYPE_SOCKET) {
  690                         ((struct socket *)fp->f_data)->so_pgid = tmp;
  691                         error =0;
  692                         goto out;
  693                 }
  694                 if (fp->f_type == DTYPE_PIPE) {
  695                         error =  fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&tmp, &context);
  696                         goto out;
  697                 }
  698 
  699                 if (tmp <= 0) {
  700                         tmp = -tmp;
  701                 } else {
  702                         proc_t p1 = proc_find(tmp);
  703                         if (p1 == 0) {
  704                                 error = ESRCH;
  705                                 goto out;
  706                         }
  707                         tmp = (int)p1->p_pgrpid;
  708                         proc_rele(p1);
  709                 }
  710                 error =  fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&tmp, &context);
  711                 goto out;
  712 
  713         case F_SETLKW:
  714                 flg |= F_WAIT;
  715                 /* Fall into F_SETLK */
  716 
  717         case F_SETLK:
  718                 if (fp->f_type != DTYPE_VNODE) {
  719                         error = EBADF;
  720                         goto out;
  721                 }
  722                 vp = (struct vnode *)fp->f_data;
  723 
  724                 fflag = fp->f_flag;
  725                 offset = fp->f_offset;
  726                 proc_fdunlock(p);
  727 
  728                 /* Copy in the lock structure */
  729                 error = copyin(argp, (caddr_t)&fl, sizeof(fl));
  730                 if (error) {
  731                         goto outdrop;
  732                 }
  733 
  734                 if ((fl.l_whence == SEEK_CUR) && (fl.l_start + offset < fl.l_start)) {
  735                     error = EOVERFLOW;
  736                     goto outdrop;
  737                 }
  738 
  739                 if ( (error = vnode_getwithref(vp)) ) {
  740                         goto outdrop;
  741                 }
  742                 if (fl.l_whence == SEEK_CUR)
  743                         fl.l_start += offset;
  744 
  745 #if CONFIG_MACF
  746                 error = mac_file_check_lock(proc_ucred(p), fp->f_fglob,
  747                     F_SETLK, &fl);
  748                 if (error) {
  749                         (void)vnode_put(vp);
  750                         goto outdrop;
  751                 }
  752 #endif
  753                 switch (fl.l_type) {
  754 
  755                 case F_RDLCK:
  756                         if ((fflag & FREAD) == 0) {
  757                                 (void)vnode_put(vp);
  758                                 error = EBADF;
  759                                 goto outdrop;
  760                         }
  761                         // XXX UInt32 unsafe for LP64 kernel
  762                         OSBitOrAtomic(P_LADVLOCK, (UInt32 *)&p->p_ladvflag);
  763                         error = VNOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg, &context);
  764                         (void)vnode_put(vp);
  765                         goto outdrop;
  766 
  767                 case F_WRLCK:
  768                         if ((fflag & FWRITE) == 0) {
  769                                 (void)vnode_put(vp);
  770                                 error = EBADF;
  771                                 goto outdrop;
  772                         }
  773                         // XXX UInt32 unsafe for LP64 kernel
  774                         OSBitOrAtomic(P_LADVLOCK, (UInt32 *)&p->p_ladvflag);
  775                         error = VNOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg, &context);
  776                         (void)vnode_put(vp);
  777                         goto outdrop;
  778 
  779                 case F_UNLCK:
  780                         error = VNOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
  781                                 F_POSIX, &context);
  782                         (void)vnode_put(vp);
  783                         goto outdrop;
  784 
  785                 default:
  786                         (void)vnode_put(vp);
  787                         error = EINVAL;
  788                         goto outdrop;
  789                 }
  790 
  791         case F_GETLK:
  792                 if (fp->f_type != DTYPE_VNODE) {
  793                         error = EBADF;
  794                         goto out;
  795                 }
  796                 vp = (struct vnode *)fp->f_data;
  797 
  798                 offset = fp->f_offset;
  799                 proc_fdunlock(p);
  800 
  801                 /* Copy in the lock structure */
  802                 error = copyin(argp, (caddr_t)&fl, sizeof(fl));
  803                 if (error)
  804                         goto outdrop;
  805 
  806                 /* Check starting byte and ending byte for EOVERFLOW in SEEK_CUR */
  807                 /* and ending byte for EOVERFLOW in SEEK_SET */
  808                 if (((fl.l_whence == SEEK_CUR) && 
  809                      ((fl.l_start + offset < fl.l_start) ||
  810                       ((fl.l_len > 0) && (fl.l_start+offset + fl.l_len - 1 < fl.l_start+offset)))) ||
  811                     ((fl.l_whence == SEEK_SET) && (fl.l_len > 0) && (fl.l_start + fl.l_len - 1 < fl.l_start)))
  812                 {
  813                         /* lf_advlock doesn't check start/end for F_GETLK if file has no locks */
  814                         error = EOVERFLOW;
  815                         goto outdrop;
  816                 }
  817 
  818                 if ((fl.l_whence == SEEK_SET) && (fl.l_start < 0)) {
  819                         error = EINVAL;
  820                         goto outdrop;
  821                 }
  822 
  823                 switch (fl.l_type) {
  824                 case F_RDLCK:
  825                 case F_UNLCK:
  826                 case F_WRLCK:
  827                         break;
  828                 default:
  829                         error = EINVAL;
  830                         goto outdrop;
  831                 }
  832 
  833                 switch (fl.l_whence) {
  834                 case SEEK_CUR:
  835                 case SEEK_SET:
  836                 case SEEK_END:
  837                         break;
  838                 default:
  839                         error = EINVAL;
  840                         goto outdrop;
  841                 }
  842 
  843                 if ( (error = vnode_getwithref(vp)) == 0 ) {
  844                         if (fl.l_whence == SEEK_CUR)
  845                                 fl.l_start += offset;
  846 
  847 #if CONFIG_MACF
  848                         error = mac_file_check_lock(proc_ucred(p), fp->f_fglob,
  849                             F_GETLK, &fl);
  850                         if (error == 0)
  851 #endif
  852                         error = VNOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX, &context);
  853 
  854                         (void)vnode_put(vp);
  855 
  856                         if (error == 0)
  857                                 error = copyout((caddr_t)&fl, argp, sizeof(fl));
  858                 }
  859                 goto outdrop;
  860 
  861         case F_PREALLOCATE: {
  862                 fstore_t alloc_struct;    /* structure for allocate command */
  863                 u_int32_t alloc_flags = 0;
  864 
  865                 if (fp->f_type != DTYPE_VNODE) {
  866                         error = EBADF;
  867                         goto out;
  868                 }
  869 
  870                 vp = (struct vnode *)fp->f_data;
  871                 proc_fdunlock(p);
  872 
  873                 /* make sure that we have write permission */
  874                 if ((fp->f_flag & FWRITE) == 0) {
  875                         error = EBADF;
  876                         goto outdrop;
  877                 }
  878 
  879                 error = copyin(argp, (caddr_t)&alloc_struct, sizeof(alloc_struct));
  880                 if (error)
  881                         goto outdrop;
  882 
  883                 /* now set the space allocated to 0 */
  884                 alloc_struct.fst_bytesalloc = 0;
  885                 
  886                 /*
  887                  * Do some simple parameter checking
  888                  */
  889 
  890                 /* set up the flags */
  891 
  892                 alloc_flags |= PREALLOCATE;
  893                 
  894                 if (alloc_struct.fst_flags & F_ALLOCATECONTIG)
  895                         alloc_flags |= ALLOCATECONTIG;
  896 
  897                 if (alloc_struct.fst_flags & F_ALLOCATEALL)
  898                         alloc_flags |= ALLOCATEALL;
  899 
  900                 /*
  901                  * Do any position mode specific stuff.  The only
  902                  * position mode  supported now is PEOFPOSMODE
  903                  */
  904 
  905                 switch (alloc_struct.fst_posmode) {
  906         
  907                 case F_PEOFPOSMODE:
  908                         if (alloc_struct.fst_offset != 0) {
  909                                 error = EINVAL;
  910                                 goto outdrop;
  911                         }
  912 
  913                         alloc_flags |= ALLOCATEFROMPEOF;
  914                         break;
  915 
  916                 case F_VOLPOSMODE:
  917                         if (alloc_struct.fst_offset <= 0) {
  918                                 error = EINVAL;
  919                                 goto outdrop;
  920                         }
  921 
  922                         alloc_flags |= ALLOCATEFROMVOL;
  923                         break;
  924 
  925                 default: {
  926                         error = EINVAL;
  927                         goto outdrop;
  928                         }
  929                 }
  930                 if ( (error = vnode_getwithref(vp)) == 0 ) {
  931                         /*
  932                          * call allocate to get the space
  933                          */
  934                         error = VNOP_ALLOCATE(vp,alloc_struct.fst_length,alloc_flags,
  935                                               &alloc_struct.fst_bytesalloc, alloc_struct.fst_offset,
  936                                               &context);
  937                         (void)vnode_put(vp);
  938 
  939                         error2 = copyout((caddr_t)&alloc_struct, argp, sizeof(alloc_struct));
  940 
  941                         if (error == 0)
  942                                 error = error2;
  943                 }
  944                 goto outdrop;
  945                 
  946                 }
  947         case F_SETSIZE:
  948                 if (fp->f_type != DTYPE_VNODE) {
  949                         error = EBADF;
  950                         goto out;
  951                 }
  952                 vp = (struct vnode *)fp->f_data;
  953                 proc_fdunlock(p);
  954 
  955                 error = copyin(argp, (caddr_t)&offset, sizeof (off_t));
  956                 if (error)
  957                         goto outdrop;
  958 
  959                 error = vnode_getwithref(vp);
  960                 if (error)
  961                         goto outdrop;
  962 
  963 #if CONFIG_MACF
  964                 error = mac_vnode_check_truncate(&context,
  965                     fp->f_fglob->fg_cred, vp);
  966                 if (error) {
  967                         (void)vnode_put(vp);
  968                         goto outdrop;
  969                 }
  970 #endif
  971                 /*
  972                  * Make sure that we are root.  Growing a file
  973                  * without zero filling the data is a security hole 
  974                  * root would have access anyway so we'll allow it
  975                  */
  976                 if (!is_suser()) {
  977                         error = EACCES;
  978                 } else {
  979                         /*
  980                          * set the file size
  981                          */
  982                         error = vnode_setsize(vp, offset, IO_NOZEROFILL,
  983                             &context);
  984                 }
  985 
  986                 (void)vnode_put(vp);
  987                 goto outdrop;
  988 
  989         case F_RDAHEAD:
  990                 if (fp->f_type != DTYPE_VNODE) {
  991                         error = EBADF;
  992                         goto out;
  993                 }
  994                 if (uap->arg)
  995                         fp->f_fglob->fg_flag &= ~FNORDAHEAD;
  996                 else
  997                         fp->f_fglob->fg_flag |= FNORDAHEAD;
  998 
  999                 goto out;
 1000 
 1001         case F_NOCACHE:
 1002                 if (fp->f_type != DTYPE_VNODE) {
 1003                         error = EBADF;
 1004                         goto out;
 1005                 }
 1006                 if (uap->arg)
 1007                         fp->f_fglob->fg_flag |= FNOCACHE;
 1008                 else
 1009                         fp->f_fglob->fg_flag &= ~FNOCACHE;
 1010 
 1011                 goto out;
 1012 
 1013         case F_GLOBAL_NOCACHE:
 1014                 if (fp->f_type != DTYPE_VNODE) {
 1015                         error = EBADF;
 1016                         goto out;
 1017                 }
 1018                 vp = (struct vnode *)fp->f_data;
 1019                 proc_fdunlock(p);
 1020 
 1021                 if ( (error = vnode_getwithref(vp)) == 0 ) {
 1022 
 1023                         *retval = vnode_isnocache(vp);
 1024 
 1025                         if (uap->arg)
 1026                                 vnode_setnocache(vp);
 1027                         else
 1028                                 vnode_clearnocache(vp);
 1029 
 1030                         (void)vnode_put(vp);
 1031                 }
 1032                 goto outdrop;
 1033 
 1034         case F_CHECK_OPENEVT:
 1035                 if (fp->f_type != DTYPE_VNODE) {
 1036                         error = EBADF;
 1037                         goto out;
 1038                 }
 1039                 vp = (struct vnode *)fp->f_data;
 1040                 proc_fdunlock(p);
 1041 
 1042                 if ( (error = vnode_getwithref(vp)) == 0 ) {
 1043 
 1044                         *retval = vnode_is_openevt(vp);
 1045 
 1046                         if (uap->arg)
 1047                                 vnode_set_openevt(vp);
 1048                         else
 1049                                 vnode_clear_openevt(vp);
 1050 
 1051                         (void)vnode_put(vp);
 1052                 }
 1053                 goto outdrop;
 1054 
 1055         case F_RDADVISE: {
 1056                 struct radvisory ra_struct;
 1057 
 1058                 if (fp->f_type != DTYPE_VNODE) {
 1059                         error = EBADF;
 1060                         goto out;
 1061                 }
 1062                 vp = (struct vnode *)fp->f_data;
 1063                 proc_fdunlock(p);
 1064 
 1065                 if ( (error = copyin(argp, (caddr_t)&ra_struct, sizeof(ra_struct))) )
 1066                         goto outdrop;
 1067                 if ( (error = vnode_getwithref(vp)) == 0 ) {
 1068                         error = VNOP_IOCTL(vp, F_RDADVISE, (caddr_t)&ra_struct, 0, &context);
 1069 
 1070                         (void)vnode_put(vp);
 1071                 }
 1072                 goto outdrop;
 1073                 }
 1074 
 1075         case F_READBOOTSTRAP:
 1076         case F_WRITEBOOTSTRAP: {
 1077                 fbootstraptransfer_t fbt_struct;
 1078                 user_fbootstraptransfer_t user_fbt_struct;
 1079                 int     sizeof_struct;
 1080                 caddr_t boot_structp;
 1081 
 1082                 if (fp->f_type != DTYPE_VNODE) {
 1083                         error = EBADF;
 1084                         goto out;
 1085                 }
 1086                 vp = (struct vnode *)fp->f_data;
 1087                 proc_fdunlock(p);
 1088 
 1089                 if (IS_64BIT_PROCESS(p)) {
 1090                         sizeof_struct = sizeof(user_fbt_struct);
 1091                         boot_structp = (caddr_t) &user_fbt_struct;
 1092                 }
 1093                 else {
 1094                         sizeof_struct = sizeof(fbt_struct);
 1095                         boot_structp = (caddr_t) &fbt_struct;
 1096                 }
 1097                 error = copyin(argp, boot_structp, sizeof_struct);
 1098                 if (error)
 1099                         goto outdrop;
 1100                 if ( (error = vnode_getwithref(vp)) ) {
 1101                         goto outdrop;
 1102                 }
 1103                 if (uap->cmd == F_WRITEBOOTSTRAP) {
 1104                         /*
 1105                          * Make sure that we are root.  Updating the
 1106                          * bootstrap on a disk could be a security hole
 1107                          */
 1108                         if (!is_suser()) {
 1109                                 (void)vnode_put(vp);
 1110                                 error = EACCES;
 1111                                 goto outdrop;
 1112                         }
 1113                 }
 1114                 if (strncmp(vnode_mount(vp)->mnt_vfsstat.f_fstypename, "hfs",
 1115                         sizeof(vnode_mount(vp)->mnt_vfsstat.f_fstypename)) != 0) {
 1116                         error = EINVAL;
 1117                 } else {
 1118                         /*
 1119                          * call vnop_ioctl to handle the I/O
 1120                          */
 1121                         error = VNOP_IOCTL(vp, uap->cmd, boot_structp, 0, &context);
 1122                 }
 1123                 (void)vnode_put(vp);
 1124                 goto outdrop;
 1125         }
 1126         case F_LOG2PHYS: {
 1127                 struct log2phys l2p_struct;    /* structure for allocate command */
 1128 
 1129                 if (fp->f_type != DTYPE_VNODE) {
 1130                         error = EBADF;
 1131                         goto out;
 1132                 }
 1133                 vp = (struct vnode *)fp->f_data;
 1134                 proc_fdunlock(p);
 1135                 if ( (error = vnode_getwithref(vp)) ) {
 1136                         goto outdrop;
 1137                 }
 1138                 error = VNOP_OFFTOBLK(vp, fp->f_offset, &lbn);
 1139                 if (error) {
 1140                         (void)vnode_put(vp);
 1141                         goto outdrop;
 1142                 }
 1143                 error = VNOP_BLKTOOFF(vp, lbn, &offset);
 1144                 if (error) {
 1145                         (void)vnode_put(vp);
 1146                         goto outdrop;
 1147                 }
 1148                 devBlockSize = vfs_devblocksize(vnode_mount(vp));
 1149 
 1150                 error = VNOP_BLOCKMAP(vp, offset, devBlockSize, &bn, NULL, NULL, 0, &context);
 1151 
 1152                 (void)vnode_put(vp);
 1153 
 1154                 if (!error) {
 1155                         l2p_struct.l2p_flags = 0;       /* for now */
 1156                         l2p_struct.l2p_contigbytes = 0; /* for now */
 1157                         l2p_struct.l2p_devoffset = bn * devBlockSize;
 1158                         l2p_struct.l2p_devoffset += fp->f_offset - offset;
 1159                         error = copyout((caddr_t)&l2p_struct, argp, sizeof(l2p_struct));
 1160                 }
 1161                 goto outdrop;
 1162                 }
 1163         case F_GETPATH: {
 1164                 char *pathbufp;
 1165                 int pathlen;
 1166 
 1167                 if (fp->f_type != DTYPE_VNODE) {
 1168                         error = EBADF;
 1169                         goto out;
 1170                 }
 1171                 vp = (struct vnode *)fp->f_data;
 1172                 proc_fdunlock(p);
 1173 
 1174                 pathlen = MAXPATHLEN;
 1175                 MALLOC(pathbufp, char *, pathlen, M_TEMP, M_WAITOK);
 1176                 if (pathbufp == NULL) {
 1177                         error = ENOMEM;
 1178                         goto outdrop;
 1179                 }
 1180                 if ( (error = vnode_getwithref(vp)) == 0 ) {
 1181                         error = vn_getpath(vp, pathbufp, &pathlen);
 1182                         (void)vnode_put(vp);
 1183 
 1184                         if (error == 0)
 1185                                 error = copyout((caddr_t)pathbufp, argp, pathlen);
 1186                 }
 1187                 FREE(pathbufp, M_TEMP);
 1188                 goto outdrop;
 1189         }
 1190 
 1191         case F_PATHPKG_CHECK: {
 1192                 char *pathbufp;
 1193                 size_t pathlen;
 1194 
 1195                 if (fp->f_type != DTYPE_VNODE) {
 1196                         error = EBADF;
 1197                         goto out;
 1198                 }
 1199                 vp = (struct vnode *)fp->f_data;
 1200                 proc_fdunlock(p);
 1201 
 1202                 pathlen = MAXPATHLEN;
 1203                 pathbufp = kalloc(MAXPATHLEN);
 1204 
 1205                 if ( (error = copyinstr(argp, pathbufp, MAXPATHLEN, &pathlen)) == 0 ) {
 1206                         if ( (error = vnode_getwithref(vp)) == 0 ) {
 1207                                 error = vn_path_package_check(vp, pathbufp, pathlen, retval);
 1208 
 1209                                 (void)vnode_put(vp);
 1210                         }
 1211                 }
 1212                 kfree(pathbufp, MAXPATHLEN);
 1213                 goto outdrop;
 1214         }
 1215 
 1216         case F_CHKCLEAN:   // used by regression tests to see if all dirty pages got cleaned by fsync()
 1217         case F_FULLFSYNC:  // fsync + flush the journal + DKIOCSYNCHRONIZECACHE
 1218         case F_FREEZE_FS:  // freeze all other fs operations for the fs of this fd
 1219         case F_THAW_FS: {  // thaw all frozen fs operations for the fs of this fd
 1220                 if (fp->f_type != DTYPE_VNODE) {
 1221                         error = EBADF;
 1222                         goto out;
 1223                 }
 1224                 vp = (struct vnode *)fp->f_data;
 1225                 proc_fdunlock(p);
 1226 
 1227                 if ( (error = vnode_getwithref(vp)) == 0 ) {
 1228                         error = VNOP_IOCTL(vp, uap->cmd, (caddr_t)NULL, 0, &context);
 1229 
 1230                         (void)vnode_put(vp);
 1231                 }
 1232                 break;
 1233         }
 1234 
 1235         /*
 1236          * SPI (private) for opening a file starting from a dir fd
 1237          */
 1238         case F_OPENFROM: {
 1239                 struct user_fopenfrom fopen;
 1240                 struct vnode_attr va;
 1241                 struct nameidata nd;
 1242                 int cmode;
 1243 
 1244                 /* Check if this isn't a valid file descriptor */
 1245                 if ((fp->f_type != DTYPE_VNODE) ||
 1246                     (fp->f_flag & FREAD) == 0) {
 1247                         error = EBADF;
 1248                         goto out;
 1249                 }
 1250                 vp = (struct vnode *)fp->f_data;
 1251                 proc_fdunlock(p);
 1252 
 1253                 if (vnode_getwithref(vp)) {
 1254                         error = ENOENT;
 1255                         goto outdrop;
 1256                 }
 1257                 
 1258                 /* Only valid for directories */
 1259                 if (vp->v_type != VDIR) {
 1260                         vnode_put(vp);
 1261                         error = ENOTDIR;
 1262                         goto outdrop;
 1263                 }
 1264 
 1265                 /* Get flags, mode and pathname arguments. */
 1266                 if (IS_64BIT_PROCESS(p)) {
 1267                         error = copyin(argp, &fopen, sizeof(fopen));
 1268                 } else {
 1269                         struct fopenfrom fopen32;
 1270 
 1271                         error = copyin(argp, &fopen32, sizeof(fopen32));
 1272                         fopen.o_flags = fopen32.o_flags;
 1273                         fopen.o_mode = fopen32.o_mode;
 1274                         fopen.o_pathname = CAST_USER_ADDR_T(fopen32.o_pathname);
 1275                 }
 1276                 if (error) {
 1277                         vnode_put(vp);
 1278                         goto outdrop;
 1279                 }
 1280                 VATTR_INIT(&va);
 1281                 /* Mask off all but regular access permissions */
 1282                 cmode = ((fopen.o_mode &~ fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
 1283                 VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
 1284 
 1285                 /* Start the lookup relative to the file descriptor's vnode. */
 1286                 NDINIT(&nd, LOOKUP, USEDVP | FOLLOW | AUDITVNPATH1, UIO_USERSPACE,
 1287                        fopen.o_pathname, &context);
 1288                 nd.ni_dvp = vp;
 1289 
 1290                 error = open1(&context, &nd, fopen.o_flags, &va, retval);
 1291 
 1292                 vnode_put(vp);
 1293                 break;
 1294         }
 1295         /*
 1296          * SPI (private) for unlinking a file starting from a dir fd
 1297          */
 1298         case F_UNLINKFROM: {
 1299                 struct nameidata nd;
 1300                 user_addr_t pathname;
 1301 
 1302                 /* Check if this isn't a valid file descriptor */
 1303                 if ((fp->f_type != DTYPE_VNODE) ||
 1304                     (fp->f_flag & FREAD) == 0) {
 1305                         error = EBADF;
 1306                         goto out;
 1307                 }
 1308                 vp = (struct vnode *)fp->f_data;
 1309                 proc_fdunlock(p);
 1310 
 1311                 if (vnode_getwithref(vp)) {
 1312                         error = ENOENT;
 1313                         goto outdrop;
 1314                 }
 1315                 
 1316                 /* Only valid for directories */
 1317                 if (vp->v_type != VDIR) {
 1318                         vnode_put(vp);
 1319                         error = ENOTDIR;
 1320                         goto outdrop;
 1321                 }
 1322 
 1323                 /* Get flags, mode and pathname arguments. */
 1324                 if (IS_64BIT_PROCESS(p)) {
 1325                         pathname = (user_addr_t)argp;
 1326                 } else {
 1327                         pathname = CAST_USER_ADDR_T(argp);
 1328                 }
 1329 
 1330                 /* Start the lookup relative to the file descriptor's vnode. */
 1331                 NDINIT(&nd, DELETE, USEDVP | AUDITVNPATH1, UIO_USERSPACE, pathname, &context);
 1332                 nd.ni_dvp = vp;
 1333 
 1334                 error = unlink1(&context, &nd, 0);
 1335                 
 1336                 vnode_put(vp);
 1337                 break;
 1338 
 1339         }
 1340 
 1341         case F_ADDSIGS: {
 1342                 struct user_fsignatures fs;
 1343                 kern_return_t kr;
 1344                 vm_address_t kernel_blob_addr;
 1345                 vm_size_t kernel_blob_size;
 1346 
 1347                 if (fp->f_type != DTYPE_VNODE) {
 1348                         error = EBADF;
 1349                         goto out;
 1350                 }
 1351                 vp = (struct vnode *)fp->f_data;
 1352                 proc_fdunlock(p);
 1353                 error = vnode_getwithref(vp);
 1354                 if (error)
 1355                         goto outdrop;
 1356 
 1357                 if (IS_64BIT_PROCESS(p)) {
 1358                         error = copyin(argp, &fs, sizeof (fs));
 1359                 } else {
 1360                         struct fsignatures fs32;
 1361 
 1362                         error = copyin(argp, &fs32, sizeof (fs32));
 1363                         fs.fs_file_start = fs32.fs_file_start;
 1364                         fs.fs_blob_start = CAST_USER_ADDR_T(fs32.fs_blob_start);
 1365                         fs.fs_blob_size = fs32.fs_blob_size;
 1366                 }
 1367 
 1368                 if (error) {
 1369                         vnode_put(vp);
 1370                         goto outdrop;
 1371                 }
 1372 
 1373 #define CS_MAX_BLOB_SIZE (1ULL * 1024 * 1024) /* XXX ? */
 1374                 if (fs.fs_blob_size > CS_MAX_BLOB_SIZE) {
 1375                         error = E2BIG;
 1376                         vnode_put(vp);
 1377                         goto outdrop;
 1378                 }
 1379 
 1380                 kernel_blob_size = CAST_DOWN(vm_size_t, fs.fs_blob_size);
 1381                 kr = kmem_alloc(kernel_map,
 1382                                 &kernel_blob_addr,
 1383                                 kernel_blob_size);
 1384                 if (kr != KERN_SUCCESS) {
 1385                         error = ENOMEM;
 1386                         vnode_put(vp);
 1387                         goto outdrop;
 1388                 }
 1389 
 1390                 error = copyin(fs.fs_blob_start,
 1391                                (void *) kernel_blob_addr,
 1392                                kernel_blob_size);
 1393                 if (error) {
 1394                         kmem_free(kernel_map,
 1395                                   kernel_blob_addr,
 1396                                   kernel_blob_size);
 1397                         vnode_put(vp);
 1398                         goto outdrop;
 1399                 }
 1400 
 1401                 error = ubc_cs_blob_add(
 1402                         vp,
 1403                         CPU_TYPE_ANY,   /* not for a specific architecture */
 1404                         fs.fs_file_start,
 1405                         kernel_blob_addr,
 1406                         kernel_blob_size);
 1407                 if (error) {
 1408                         kmem_free(kernel_map,
 1409                                   kernel_blob_addr,
 1410                                   kernel_blob_size);
 1411                 } else {
 1412                         /* ubc_blob_add() was consumed "kernel_blob_addr" */
 1413                 }
 1414 
 1415                 (void) vnode_put(vp);
 1416                 break;
 1417         }
 1418 
 1419         case F_MARKDEPENDENCY: {
 1420                 struct vnode *root_vp;
 1421                 struct vnode_attr va;
 1422                 vfs_context_t ctx = vfs_context_current();
 1423                 kauth_cred_t cred;
 1424 
 1425                 if ((current_proc()->p_flag & P_DEPENDENCY_CAPABLE) == 0) {
 1426                     error = EPERM;
 1427                     goto out;
 1428                 }
 1429                 
 1430                 if (fp->f_type != DTYPE_VNODE) {
 1431                         error = EBADF;
 1432                         goto out;
 1433                 }
 1434 
 1435                 vp = (struct vnode *)fp->f_data;
 1436                 proc_fdunlock(p);
 1437 
 1438                 if (vnode_getwithref(vp)) {
 1439                         error = ENOENT;
 1440                         goto outdrop;
 1441                 }
 1442 
 1443                 // the passed in vnode must be the root dir of the file system
 1444                 if (VFS_ROOT(vp->v_mount, &root_vp, ctx) != 0 || vp != root_vp) {
 1445                     error = EINVAL;
 1446                     vnode_put(vp);
 1447                     goto outdrop;
 1448                 }
 1449                 vnode_put(root_vp);
 1450 
 1451                 // get the owner of the root dir
 1452                 VATTR_INIT(&va);
 1453                 VATTR_WANTED(&va, va_uid);
 1454                 if (vnode_getattr(vp, &va, ctx) != 0) {
 1455                     error = EINVAL;
 1456                     vnode_put(vp);
 1457                     goto outdrop;
 1458                 }
 1459 
 1460                 // and last, check that the caller is the super user or
 1461                 // the owner of the mount point
 1462                 cred = vfs_context_ucred(ctx);
 1463                 if (!is_suser() && va.va_uid != kauth_cred_getuid(cred)) {
 1464                         error = EACCES;
 1465                         vnode_put(vp);
 1466                         goto outdrop;
 1467                 }
 1468 
 1469                 // if all those checks pass then we can mark the dependency
 1470                 vfs_markdependency(vp->v_mount);
 1471                 error = 0;
 1472 
 1473                 vnode_put(vp);
 1474                 
 1475                 break;
 1476         }
 1477 
 1478         default:
 1479                 if (uap->cmd < FCNTL_FS_SPECIFIC_BASE) {
 1480                         error = EINVAL;
 1481                         goto out;
 1482                 }
 1483 
 1484                 // if it's a fs-specific fcntl() then just pass it through
 1485 
 1486                 if (fp->f_type != DTYPE_VNODE) {
 1487                         error = EBADF;
 1488                         goto out;
 1489                 }
 1490                 vp = (struct vnode *)fp->f_data;
 1491                 proc_fdunlock(p);
 1492 
 1493                 if ( (error = vnode_getwithref(vp)) == 0 ) {
 1494                         error = VNOP_IOCTL(vp, uap->cmd, CAST_DOWN(caddr_t, argp), 0, &context);
 1495 
 1496                         (void)vnode_put(vp);
 1497                 }
 1498                 break;
 1499         
 1500         }
 1501 
 1502 outdrop:
 1503         AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
 1504         fp_drop(p, fd, fp, 0);
 1505         return(error);
 1506 out:
 1507         fp_drop(p, fd, fp, 1);
 1508         proc_fdunlock(p);
 1509         return(error);
 1510 }
 1511 
 1512 
 1513 /*
 1514  * finishdup
 1515  *
 1516  * Description: Common code for dup, dup2, and fcntl(F_DUPFD).
 1517  *
 1518  * Parameters:  p                               Process performing the dup
 1519  *              old                             The fd to dup
 1520  *              new                             The fd to dup it to
 1521  *              retval                          Pointer to the call return area
 1522  *
 1523  * Returns:     0                               Success
 1524  *              EBADF
 1525  *              ENOMEM
 1526  *
 1527  * Implicit returns:
 1528  *              *retval (modified)              The new descriptor
 1529  *
 1530  * Locks:       Assumes proc_fdlock for process pointing to fdp is held by
 1531  *              the caller
 1532  *
 1533  * Notes:       This function may drop and reacquire this lock; it is unsafe
 1534  *              for a caller to assume that other state protected by the lock
 1535  *              has not been subsequently changes out from under it.
 1536  */
 1537 int
 1538 finishdup(proc_t p, struct filedesc *fdp, int old, int new, register_t *retval)
 1539 {
 1540         struct fileproc *nfp;
 1541         struct fileproc *ofp;
 1542 #if CONFIG_MACF
 1543         int error;
 1544 #endif
 1545 
 1546 #if DIAGNOSTIC
 1547         proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
 1548 #endif
 1549 
 1550         if ((ofp = fdp->fd_ofiles[old]) == NULL ||
 1551                         (fdp->fd_ofileflags[old] & UF_RESERVED)) {
 1552                 fdrelse(p, new);
 1553                 return (EBADF);
 1554         }
 1555         fg_ref(ofp);
 1556 
 1557 #if CONFIG_MACF
 1558         error = mac_file_check_dup(proc_ucred(p), ofp->f_fglob, new);
 1559         if (error) {
 1560                 fg_drop(ofp);
 1561                 fdrelse(p, new);
 1562                 return (error);
 1563         }
 1564 #endif
 1565 
 1566         proc_fdunlock(p);
 1567 
 1568         MALLOC_ZONE(nfp, struct fileproc *, sizeof(struct fileproc), M_FILEPROC, M_WAITOK);
 1569         /* Failure check follows proc_fdlock() due to handling requirements */
 1570 
 1571         proc_fdlock(p);
 1572 
 1573         if (nfp == NULL) {
 1574                 fg_drop(ofp);
 1575                 fdrelse(p, new);
 1576                 return (ENOMEM);
 1577         }
 1578 
 1579         bzero(nfp, sizeof(struct fileproc));
 1580 
 1581         nfp->f_flags = 0;
 1582         nfp->f_fglob = ofp->f_fglob;
 1583         nfp->f_iocount = 0;
 1584 
 1585 #if DIAGNOSTIC
 1586         if (fdp->fd_ofiles[new] != 0)
 1587                 panic("finishdup: overwriting fd_ofiles with new %d\n", new);
 1588         if ((fdp->fd_ofileflags[new] & UF_RESERVED) == 0)
 1589                 panic("finishdup: unreserved  fileflags  with new %d\n", new);
 1590 #endif
 1591 
 1592         if (new > fdp->fd_lastfile)
 1593                 fdp->fd_lastfile = new;
 1594         procfdtbl_releasefd(p, new, nfp);
 1595         *retval = new;
 1596         return (0);
 1597 }
 1598 
 1599 
 1600 /*
 1601  * close
 1602  *
 1603  * Description: The implementation of the close(2) system call
 1604  *
 1605  * Parameters:  p                       Process in whose per process file table
 1606  *                                      the close is to occur
 1607  *              uap->fd                 fd to be closed
 1608  *              retval                  <unused>
 1609  *
 1610  * Returns:     0                       Success
 1611  *      fp_lookup:EBADF                 Bad file descriptor
 1612  *      close_internal:EBADF
 1613  *      close_internal:???              Anything returnable by a per-fileops
 1614  *                                      close function
 1615  */
 1616 int
 1617 close(proc_t p, struct close_args *uap, register_t *retval)
 1618 {
 1619         __pthread_testcancel(1);
 1620         return(close_nocancel(p, (struct close_nocancel_args *)uap, retval));
 1621 }
 1622 
 1623 
 1624 int
 1625 close_nocancel(proc_t p, struct close_nocancel_args *uap, __unused register_t *retval)
 1626 {
 1627         struct fileproc *fp;
 1628         int fd = uap->fd;
 1629         int error =0;
 1630 
 1631         AUDIT_SYSCLOSE(p, fd);
 1632 
 1633         proc_fdlock(p);
 1634 
 1635         if ( (error = fp_lookup(p,fd,&fp, 1)) ) {
 1636                 proc_fdunlock(p);
 1637                 return(error);
 1638         }
 1639 
 1640         error = close_internal_locked(p, fd, fp, 0);
 1641 
 1642         proc_fdunlock(p);
 1643 
 1644         return(error);
 1645 }
 1646 
 1647 
 1648 /*
 1649  * close_internal_locked
 1650  *
 1651  * Close a file descriptor.
 1652  *
 1653  * Parameters:  p                       Process in whose per process file table
 1654  *                                      the close is to occur
 1655  *              fd                      fd to be closed
 1656  *              fp                      fileproc associated with the fd
 1657  *
 1658  * Returns:     0                       Success
 1659  *              EBADF                   fd already in close wait state
 1660  *      closef_locked:???               Anything returnable by a per-fileops
 1661  *                                      close function
 1662  *
 1663  * Locks:       Assumes proc_fdlock for process is held by the caller and returns
 1664  *              with lock held
 1665  *
 1666  * Notes:       This function may drop and reacquire this lock; it is unsafe
 1667  *              for a caller to assume that other state protected by the lock
 1668  *              has not been subsequently changes out from under it, if the
 1669  *              caller made the call with the lock held.
 1670  */
 1671 static int
 1672 close_internal_locked(proc_t p, int fd, struct fileproc *fp, int flags)
 1673 {
 1674         struct filedesc *fdp = p->p_fd;
 1675         int error =0;
 1676         int resvfd = flags & FD_DUP2RESV;
 1677 
 1678 
 1679 #if DIAGNOSTIC
 1680         proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
 1681 #endif
 1682 
 1683         /* Keep people from using the filedesc while we are closing it */
 1684         procfdtbl_markclosefd(p, fd);
 1685 
 1686 
 1687         if ((fp->f_flags & FP_CLOSING) == FP_CLOSING) {
 1688                 panic("close_internal_locked:  being called on already closing fd\n");
 1689         }
 1690 
 1691 
 1692 #if DIAGNOSTIC
 1693         if ((fdp->fd_ofileflags[fd] & UF_RESERVED) == 0)
 1694                 panic("close_internal: unreserved  fileflags  with fd %d\n", fd);
 1695 #endif
 1696 
 1697         fp->f_flags |= FP_CLOSING;
 1698 
 1699         if ( (fp->f_flags & FP_AIOISSUED) || kauth_authorize_fileop_has_listeners() ) {
 1700 
 1701                 proc_fdunlock(p);
 1702 
 1703                 if ( (fp->f_type == DTYPE_VNODE) && kauth_authorize_fileop_has_listeners() ) {
 1704                         /*
 1705                          * call out to allow 3rd party notification of close. 
 1706                          * Ignore result of kauth_authorize_fileop call.
 1707                          */
 1708                         if (vnode_getwithref((vnode_t)fp->f_data) == 0) {
 1709                                 u_int   fileop_flags = 0;
 1710                                 if ((fp->f_flags & FP_WRITTEN) != 0)
 1711                                         fileop_flags |= KAUTH_FILEOP_CLOSE_MODIFIED;
 1712                                 kauth_authorize_fileop(fp->f_fglob->fg_cred, KAUTH_FILEOP_CLOSE, 
 1713                                                        (uintptr_t)fp->f_data, (uintptr_t)fileop_flags);
 1714                                 vnode_put((vnode_t)fp->f_data);
 1715                         }
 1716                 }
 1717                 if (fp->f_flags & FP_AIOISSUED)
 1718                         /*
 1719                          * cancel all async IO requests that can be cancelled.
 1720                          */
 1721                         _aio_close( p, fd );
 1722 
 1723                 proc_fdlock(p);
 1724         }
 1725 
 1726         if (fd < fdp->fd_knlistsize)
 1727                 knote_fdclose(p, fd);
 1728 
 1729         if (fp->f_flags & FP_WAITEVENT) 
 1730                 (void)waitevent_close(p, fp);
 1731 
 1732         if ((fp->f_flags & FP_INCHRREAD) == 0)
 1733                 fileproc_drain(p, fp);
 1734 
 1735         if (resvfd == 0)
 1736                 _fdrelse(p, fd);
 1737 
 1738         error = closef_locked(fp, fp->f_fglob, p);
 1739         if ((fp->f_flags & FP_WAITCLOSE) == FP_WAITCLOSE)
 1740                 wakeup(&fp->f_flags);
 1741         fp->f_flags &= ~(FP_WAITCLOSE | FP_CLOSING);
 1742 
 1743         proc_fdunlock(p);
 1744 
 1745         FREE_ZONE(fp, sizeof(*fp), M_FILEPROC); 
 1746 
 1747         proc_fdlock(p);
 1748 
 1749 #if DIAGNOSTIC
 1750         if (resvfd != 0) {
 1751                 if ((fdp->fd_ofileflags[fd] & UF_RESERVED) == 0)
 1752                         panic("close with reserved fd returns with freed fd:%d: proc: %x\n", fd, (unsigned int)p);
 1753         }
 1754 #endif
 1755 
 1756         return(error);
 1757 }
 1758 
 1759 
 1760 /*
 1761  * fstat1
 1762  *
 1763  * Description: Return status information about a file descriptor.
 1764  *
 1765  * Parameters:  p                               The process doing the fstat
 1766  *              fd                              The fd to stat
 1767  *              ub                              The user stat buffer
 1768  *              xsecurity                       The user extended security
 1769  *                                              buffer, or 0 if none
 1770  *              xsecurity_size                  The size of xsecurity, or 0
 1771  *                                              if no xsecurity
 1772  *              isstat64                        Flag to indicate 64 bit version
 1773  *                                              for inode size, etc.
 1774  *
 1775  * Returns:     0                               Success
 1776  *              EBADF
 1777  *              EFAULT
 1778  *      fp_lookup:EBADF                         Bad file descriptor
 1779  *      vnode_getwithref:???
 1780  *      copyout:EFAULT
 1781  *      vnode_getwithref:???
 1782  *      vn_stat:???
 1783  *      soo_stat:???
 1784  *      pipe_stat:???
 1785  *      pshm_stat:???
 1786  *      kqueue_stat:???
 1787  *
 1788  * Notes:       Internal implementation for all other fstat() related
 1789  *              functions
 1790  *
 1791  *              XXX switch on node type is bogus; need a stat in struct
 1792  *              XXX fileops instead.
 1793  */
 1794 static int
 1795 fstat1(proc_t p, int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size, int isstat64)
 1796 {
 1797         struct fileproc *fp;
 1798         struct stat sb;
 1799         struct stat64 sb64;
 1800         struct user_stat user_sb;
 1801         struct user_stat64 user_sb64;
 1802         int error, my_size;
 1803         int funnel_state;
 1804         file_type_t type;
 1805         caddr_t data;
 1806         kauth_filesec_t fsec;
 1807         user_size_t xsecurity_bufsize;
 1808         vfs_context_t ctx = vfs_context_current();
 1809         void * sbptr;
 1810 
 1811 
 1812         AUDIT_ARG(fd, fd);
 1813 
 1814         if ((error = fp_lookup(p, fd, &fp, 0)) != 0) {
 1815                 return(error);
 1816         }
 1817         type = fp->f_type;
 1818         data = fp->f_data;
 1819         fsec = KAUTH_FILESEC_NONE;
 1820 
 1821         sbptr = (isstat64 != 0) ? (void *)&sb64: (void *)&sb;
 1822 
 1823         switch (type) {
 1824 
 1825         case DTYPE_VNODE:
 1826                 if ((error = vnode_getwithref((vnode_t)data)) == 0) {
 1827                         /*
 1828                          * If the caller has the file open, and is not
 1829                          * requesting extended security information, we are
 1830                          * going to let them get the basic stat information.
 1831                          */
 1832                         if (xsecurity == USER_ADDR_NULL) {
 1833                                 error = vn_stat_noauth((vnode_t)data, sbptr, NULL, isstat64, ctx);
 1834                         } else {
 1835                                 error = vn_stat((vnode_t)data, sbptr, &fsec, isstat64, ctx);
 1836                         }
 1837 
 1838                         AUDIT_ARG(vnpath, (struct vnode *)data, ARG_VNODE1);
 1839                         (void)vnode_put((vnode_t)data);
 1840                 }
 1841                 break;
 1842 
 1843 #if SOCKETS
 1844         case DTYPE_SOCKET:
 1845                 error = soo_stat((struct socket *)data, sbptr, isstat64);
 1846                 break;
 1847 #endif /* SOCKETS */
 1848 
 1849         case DTYPE_PIPE:
 1850                 error = pipe_stat((void *)data, sbptr, isstat64);
 1851                 break;
 1852 
 1853         case DTYPE_PSXSHM:
 1854                 error = pshm_stat((void *)data, sbptr, isstat64);
 1855                 break;
 1856 
 1857         case DTYPE_KQUEUE:
 1858                 funnel_state = thread_funnel_set(kernel_flock, TRUE);
 1859                 error = kqueue_stat(fp, sbptr, isstat64, p);
 1860                 thread_funnel_set(kernel_flock, funnel_state);
 1861                 break;
 1862 
 1863         default:
 1864                 error = EBADF;
 1865                 goto out;
 1866         }
 1867         if (error == 0) {
 1868                 caddr_t sbp;
 1869 
 1870                 if (isstat64 != 0) {
 1871                         sb64.st_lspare = 0;
 1872                         sb64.st_qspare[0] = 0LL;
 1873                         sb64.st_qspare[1] = 0LL;
 1874                         if (IS_64BIT_PROCESS(current_proc())) {
 1875                                 munge_stat64(&sb64, &user_sb64); 
 1876                                 my_size = sizeof(user_sb64);
 1877                                 sbp = (caddr_t)&user_sb64;
 1878                         } else {
 1879                                 my_size = sizeof(sb64);
 1880                                 sbp = (caddr_t)&sb64;
 1881                         }
 1882                 } else {
 1883                         sb.st_lspare = 0;
 1884                         sb.st_qspare[0] = 0LL;
 1885                         sb.st_qspare[1] = 0LL;
 1886                         if (IS_64BIT_PROCESS(current_proc())) {
 1887                                 munge_stat(&sb, &user_sb); 
 1888                                 my_size = sizeof(user_sb);
 1889                                 sbp = (caddr_t)&user_sb;
 1890                         } else {
 1891                                 my_size = sizeof(sb);
 1892                                 sbp = (caddr_t)&sb;
 1893                         }
 1894                 }
 1895 
 1896                 error = copyout(sbp, ub, my_size);
 1897         }
 1898 
 1899         /* caller wants extended security information? */
 1900         if (xsecurity != USER_ADDR_NULL) {
 1901 
 1902                 /* did we get any? */
 1903                  if (fsec == KAUTH_FILESEC_NONE) {
 1904                         if (susize(xsecurity_size, 0) != 0) {
 1905                                 error = EFAULT;
 1906                                 goto out;
 1907                         }
 1908                 } else {
 1909                         /* find the user buffer size */
 1910                         xsecurity_bufsize = fusize(xsecurity_size);
 1911 
 1912                         /* copy out the actual data size */
 1913                         if (susize(xsecurity_size, KAUTH_FILESEC_COPYSIZE(fsec)) != 0) {
 1914                                 error = EFAULT;
 1915                                 goto out;
 1916                         }
 1917 
 1918                         /* if the caller supplied enough room, copy out to it */
 1919                         if (xsecurity_bufsize >= KAUTH_FILESEC_COPYSIZE(fsec))
 1920                                 error = copyout(fsec, xsecurity, KAUTH_FILESEC_COPYSIZE(fsec));
 1921                 }
 1922         }
 1923 out:
 1924         fp_drop(p, fd, fp, 0);
 1925         if (fsec != NULL)
 1926                 kauth_filesec_free(fsec);
 1927         return (error);
 1928 }
 1929 
 1930 
 1931 /*
 1932  * fstat_extended
 1933  *
 1934  * Description: Extended version of fstat supporting returning extended
 1935  *              security information
 1936  *
 1937  * Parameters:  p                               The process doing the fstat
 1938  *              uap->fd                         The fd to stat
 1939  *              uap->ub                         The user stat buffer
 1940  *              uap->xsecurity                  The user extended security
 1941  *                                              buffer, or 0 if none
 1942  *              uap->xsecurity_size             The size of xsecurity, or 0
 1943  *
 1944  * Returns:     0                               Success
 1945  *              !0                              Errno (see fstat1)
 1946  */
 1947 int
 1948 fstat_extended(proc_t p, struct fstat_extended_args *uap, __unused register_t *retval)
 1949 {
 1950         return(fstat1(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size, 0));
 1951 }
 1952  
 1953 
 1954 /*
 1955  * fstat
 1956  *
 1957  * Description: Get file status for the file associated with fd
 1958  *
 1959  * Parameters:  p                               The process doing the fstat
 1960  *              uap->fd                         The fd to stat
 1961  *              uap->ub                         The user stat buffer
 1962  *
 1963  * Returns:     0                               Success
 1964  *              !0                              Errno (see fstat1)
 1965  */
 1966 int
 1967 fstat(proc_t p, register struct fstat_args *uap, __unused register_t *retval)
 1968 {
 1969         return(fstat1(p, uap->fd, uap->ub, 0, 0, 0));
 1970 }
 1971 
 1972 
 1973 /*
 1974  * fstat64_extended
 1975  *
 1976  * Description: Extended version of fstat64 supporting returning extended
 1977  *              security information
 1978  *
 1979  * Parameters:  p                               The process doing the fstat
 1980  *              uap->fd                         The fd to stat
 1981  *              uap->ub                         The user stat buffer
 1982  *              uap->xsecurity                  The user extended security
 1983  *                                              buffer, or 0 if none
 1984  *              uap->xsecurity_size             The size of xsecurity, or 0
 1985  *
 1986  * Returns:     0                               Success
 1987  *              !0                              Errno (see fstat1)
 1988  */
 1989 int
 1990 fstat64_extended(proc_t p, struct fstat64_extended_args *uap, __unused register_t *retval)
 1991 {
 1992         return(fstat1(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size, 1));
 1993 }
 1994  
 1995 
 1996 /*
 1997  * fstat64
 1998  *
 1999  * Description: Get 64 bit version of the file status for the file associated
 2000  *              with fd
 2001  *
 2002  * Parameters:  p                               The process doing the fstat
 2003  *              uap->fd                         The fd to stat
 2004  *              uap->ub                         The user stat buffer
 2005  *
 2006  * Returns:     0                               Success
 2007  *              !0                              Errno (see fstat1)
 2008  */
 2009 int
 2010 fstat64(proc_t p, register struct fstat64_args *uap, __unused register_t *retval)
 2011 {
 2012         return(fstat1(p, uap->fd, uap->ub, 0, 0, 1));
 2013 }
 2014 
 2015 
 2016 /*
 2017  * fpathconf
 2018  *
 2019  * Description: Return pathconf information about a file descriptor.
 2020  *
 2021  * Parameters:  p                               Process making the request
 2022  *              uap->fd                         fd to get information about
 2023  *              uap->name                       Name of information desired
 2024  *              retval                          Pointer to the call return area
 2025  *
 2026  * Returns:     0                               Success
 2027  *              EINVAL
 2028  *      fp_lookup:EBADF                         Bad file descriptor
 2029  *      vnode_getwithref:???
 2030  *      vn_pathconf:???
 2031  *
 2032  * Implicit returns:
 2033  *              *retval (modified)              Returned information (numeric)
 2034  */
 2035 int
 2036 fpathconf(proc_t p, struct fpathconf_args *uap, register_t *retval)
 2037 {
 2038         int fd = uap->fd;
 2039         struct fileproc *fp;
 2040         struct vnode *vp;
 2041         int error = 0;
 2042         file_type_t type;
 2043         caddr_t data;
 2044 
 2045 
 2046         AUDIT_ARG(fd, uap->fd);
 2047         if ( (error = fp_lookup(p, fd, &fp, 0)) )
 2048                 return(error);
 2049         type = fp->f_type;
 2050         data = fp->f_data;
 2051 
 2052         switch (type) {
 2053 
 2054         case DTYPE_SOCKET:
 2055                 if (uap->name != _PC_PIPE_BUF) {
 2056                         error = EINVAL;
 2057                         goto out;
 2058                 }
 2059                 *retval = PIPE_BUF;
 2060                 error = 0;
 2061                 goto out;
 2062 
 2063         case DTYPE_PIPE:
 2064                 *retval = PIPE_BUF;
 2065                 error = 0;
 2066                 goto out;
 2067 
 2068         case DTYPE_VNODE:
 2069                 vp = (struct vnode *)data;
 2070 
 2071                 if ( (error = vnode_getwithref(vp)) == 0) {
 2072                         AUDIT_ARG(vnpath, vp, ARG_VNODE1);
 2073 
 2074                         error = vn_pathconf(vp, uap->name, retval, vfs_context_current());
 2075 
 2076                         (void)vnode_put(vp);
 2077                 }
 2078                 goto out;
 2079 
 2080         case DTYPE_PSXSHM:
 2081         case DTYPE_PSXSEM:
 2082         case DTYPE_KQUEUE:
 2083         case DTYPE_FSEVENTS:
 2084                 error = EINVAL;
 2085                 goto out;
 2086 
 2087         }
 2088         /*NOTREACHED*/
 2089 out:
 2090         fp_drop(p, fd, fp, 0);
 2091         return(error);
 2092 }
 2093 
 2094 /*
 2095  * Statistics counter for the number of times a process calling fdalloc()
 2096  * has resulted in an expansion of the per process open file table.
 2097  *
 2098  * XXX This would likely be of more use if it were per process
 2099  */
 2100 int fdexpand;
 2101 
 2102 
 2103 /*
 2104  * fdalloc
 2105  *
 2106  * Description: Allocate a file descriptor for the process.
 2107  *
 2108  * Parameters:  p                               Process to allocate the fd in
 2109  *              want                            The fd we would prefer to get
 2110  *              result                          Pointer to fd we got
 2111  *
 2112  * Returns:     0                               Success
 2113  *              EMFILE
 2114  *              ENOMEM
 2115  *
 2116  * Implicit returns:
 2117  *              *result (modified)              The fd which was allocated
 2118  */
 2119 int
 2120 fdalloc(proc_t p, int want, int *result)
 2121 {
 2122         struct filedesc *fdp = p->p_fd;
 2123         int i;
 2124         int lim, last, numfiles, oldnfiles;
 2125         struct fileproc **newofiles, **ofiles;
 2126         char *newofileflags;
 2127 
 2128         /*
 2129          * Search for a free descriptor starting at the higher
 2130          * of want or fd_freefile.  If that fails, consider
 2131          * expanding the ofile array.
 2132          */
 2133 #if DIAGNOSTIC
 2134         proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
 2135 #endif
 2136 
 2137         lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
 2138         for (;;) {
 2139                 last = min(fdp->fd_nfiles, lim);
 2140                 if ((i = want) < fdp->fd_freefile)
 2141                         i = fdp->fd_freefile;
 2142                 for (; i < last; i++) {
 2143                         if (fdp->fd_ofiles[i] == NULL && !(fdp->fd_ofileflags[i] & UF_RESERVED)) {
 2144                                 procfdtbl_reservefd(p, i);
 2145                                 if (i > fdp->fd_lastfile)
 2146                                         fdp->fd_lastfile = i;
 2147                                 if (want <= fdp->fd_freefile)
 2148                                         fdp->fd_freefile = i;
 2149                                 *result = i;
 2150                                 return (0);
 2151                         }
 2152                 }
 2153 
 2154                 /*
 2155                  * No space in current array.  Expand?
 2156                  */
 2157                 if (fdp->fd_nfiles >= lim)
 2158                         return (EMFILE);
 2159                 if (fdp->fd_nfiles < NDEXTENT)
 2160                         numfiles = NDEXTENT;
 2161                 else
 2162                         numfiles = 2 * fdp->fd_nfiles;
 2163                 /* Enforce lim */
 2164                 if (numfiles > lim)
 2165                         numfiles = lim;
 2166                 proc_fdunlock(p);
 2167                 MALLOC_ZONE(newofiles, struct fileproc **,
 2168                                 numfiles * OFILESIZE, M_OFILETABL, M_WAITOK);
 2169                 proc_fdlock(p);
 2170                 if (newofiles == NULL) {
 2171                         return (ENOMEM);
 2172                 }
 2173                 if (fdp->fd_nfiles >= numfiles) {
 2174                         FREE_ZONE(newofiles, numfiles * OFILESIZE, M_OFILETABL);
 2175                         continue;
 2176                 }
 2177                 newofileflags = (char *) &newofiles[numfiles];
 2178                 /*
 2179                  * Copy the existing ofile and ofileflags arrays
 2180                  * and zero the new portion of each array.
 2181                  */
 2182                 oldnfiles = fdp->fd_nfiles;
 2183                 (void) memcpy(newofiles, fdp->fd_ofiles,
 2184                                 oldnfiles * sizeof(*fdp->fd_ofiles));
 2185                 (void) memset(&newofiles[oldnfiles], 0,
 2186                                 (numfiles - oldnfiles) * sizeof(*fdp->fd_ofiles));
 2187 
 2188                 (void) memcpy(newofileflags, fdp->fd_ofileflags,
 2189                                 oldnfiles * sizeof(*fdp->fd_ofileflags));
 2190                 (void) memset(&newofileflags[oldnfiles], 0,
 2191                                 (numfiles - oldnfiles) *
 2192                                                 sizeof(*fdp->fd_ofileflags));
 2193                 ofiles = fdp->fd_ofiles;
 2194                 fdp->fd_ofiles = newofiles;
 2195                 fdp->fd_ofileflags = newofileflags;
 2196                 fdp->fd_nfiles = numfiles;
 2197                 FREE_ZONE(ofiles, oldnfiles * OFILESIZE, M_OFILETABL);
 2198                 fdexpand++;
 2199         }
 2200 }
 2201 
 2202 
 2203 /*
 2204  * fdavail
 2205  *
 2206  * Description: Check to see whether n user file descriptors are available
 2207  *              to the process p.
 2208  *
 2209  * Parameters:  p                               Process to check in
 2210  *              n                               The number of fd's desired
 2211  *
 2212  * Returns:     0                               No
 2213  *              1                               Yes
 2214  *
 2215  * Locks:       Assumes proc_fdlock for process is held by the caller
 2216  *
 2217  * Notes:       The answer only remains valid so long as the proc_fdlock is
 2218  *              held by the caller.
 2219  */
 2220 int
 2221 fdavail(proc_t p, int n)
 2222 {
 2223         struct filedesc *fdp = p->p_fd;
 2224         struct fileproc **fpp;
 2225         char *flags;
 2226         int i, lim;
 2227 
 2228         lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
 2229         if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0)
 2230                 return (1);
 2231         fpp = &fdp->fd_ofiles[fdp->fd_freefile];
 2232         flags = &fdp->fd_ofileflags[fdp->fd_freefile];
 2233         for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++, flags++)
 2234                 if (*fpp == NULL && !(*flags & UF_RESERVED) && --n <= 0)
 2235                         return (1);
 2236         return (0);
 2237 }
 2238 
 2239 
 2240 /*
 2241  * fdrelse
 2242  *
 2243  * Description: Legacy KPI wrapper function for _fdrelse
 2244  *
 2245  * Parameters:  p                               Process in which fd lives
 2246  *              fd                              fd to free
 2247  *
 2248  * Returns:     void
 2249  *
 2250  * Locks:       Assumes proc_fdlock for process is held by the caller
 2251  */
 2252 void
 2253 fdrelse(proc_t p, int fd)
 2254 {
 2255         _fdrelse(p, fd);
 2256 }
 2257 
 2258 
 2259 /*
 2260  * fdgetf_noref
 2261  *
 2262  * Description: Get the fileproc pointer for the given fd from the per process
 2263  *              open file table without taking an explicit reference on it.
 2264  *
 2265  * Parameters:  p                               Process containing fd
 2266  *              fd                              fd to obtain fileproc for
 2267  *              resultfp                        Pointer to pointer return area
 2268  *
 2269  * Returns:     0                               Success
 2270  *              EBADF
 2271  *
 2272  * Implicit returns:
 2273  *              *resultfp (modified)            Pointer to fileproc pointer
 2274  *
 2275  * Locks:       Assumes proc_fdlock for process is held by the caller
 2276  *
 2277  * Notes:       Because there is no reference explicitly taken, the returned
 2278  *              fileproc pointer is only valid so long as the proc_fdlock
 2279  *              remains held by the caller.
 2280  */
 2281 int
 2282 fdgetf_noref(proc_t p, int fd, struct fileproc **resultfp)
 2283 {
 2284         struct filedesc *fdp = p->p_fd;
 2285         struct fileproc *fp;
 2286 
 2287         if (fd < 0 || fd >= fdp->fd_nfiles ||
 2288                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2289                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2290                 return (EBADF);
 2291         }
 2292         if (resultfp)
 2293                 *resultfp = fp;
 2294         return (0);
 2295 }
 2296 
 2297 
 2298 /*
 2299  * fp_getfvp
 2300  *
 2301  * Description: Get fileproc and vnode pointer for a given fd from the per
 2302  *              process open file table of the specified process, and if
 2303  *              successful, increment the f_iocount
 2304  *
 2305  * Parameters:  p                               Process in which fd lives
 2306  *              fd                              fd to get information for
 2307  *              resultfp                        Pointer to result fileproc
 2308  *                                              pointer area, or 0 if none
 2309  *              resultvp                        Pointer to result vnode pointer
 2310  *                                              area, or 0 if none
 2311  *
 2312  * Returns:     0                               Success
 2313  *              EBADF                           Bad file descriptor
 2314  *              ENOTSUP                         fd does not refer to a vnode
 2315  *
 2316  * Implicit returns:
 2317  *              *resultfp (modified)            Fileproc pointer
 2318  *              *resultvp (modified)            vnode pointer
 2319  *
 2320  * Notes:       The resultfp and resultvp fields are optional, and may be
 2321  *              independently specified as NULL to skip returning information
 2322  *
 2323  * Locks:       Internally takes and releases proc_fdlock
 2324  */
 2325 int
 2326 fp_getfvp(proc_t p, int fd, struct fileproc **resultfp, struct vnode **resultvp)
 2327 {
 2328         struct filedesc *fdp = p->p_fd;
 2329         struct fileproc *fp;
 2330 
 2331         proc_fdlock_spin(p);
 2332         if (fd < 0 || fd >= fdp->fd_nfiles ||
 2333                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2334                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2335                 proc_fdunlock(p);
 2336                 return (EBADF);
 2337         }
 2338         if (fp->f_type != DTYPE_VNODE) {
 2339                 proc_fdunlock(p);
 2340                 return(ENOTSUP);
 2341         }
 2342         fp->f_iocount++;
 2343 
 2344         if (resultfp)
 2345                 *resultfp = fp;
 2346         if (resultvp)
 2347                 *resultvp = (struct vnode *)fp->f_data;
 2348         proc_fdunlock(p);
 2349 
 2350         return (0);
 2351 }
 2352 
 2353 
 2354 /*
 2355  * fp_getfvpandvid
 2356  *
 2357  * Description: Get fileproc, vnode pointer, and vid for a given fd from the
 2358  *              per process open file table of the specified process, and if
 2359  *              successful, increment the f_iocount
 2360  *
 2361  * Parameters:  p                               Process in which fd lives
 2362  *              fd                              fd to get information for
 2363  *              resultfp                        Pointer to result fileproc
 2364  *                                              pointer area, or 0 if none
 2365  *              resultvp                        Pointer to result vnode pointer
 2366  *                                              area, or 0 if none
 2367  *              vidp                            Pointer to resuld vid area
 2368  *
 2369  * Returns:     0                               Success
 2370  *              EBADF                           Bad file descriptor
 2371  *              ENOTSUP                         fd does not refer to a vnode
 2372  *
 2373  * Implicit returns:
 2374  *              *resultfp (modified)            Fileproc pointer
 2375  *              *resultvp (modified)            vnode pointer
 2376  *              *vidp                           vid value
 2377  *
 2378  * Notes:       The resultfp and resultvp fields are optional, and may be
 2379  *              independently specified as NULL to skip returning information
 2380  *
 2381  * Locks:       Internally takes and releases proc_fdlock
 2382  */
 2383 int
 2384 fp_getfvpandvid(proc_t p, int fd, struct fileproc **resultfp,
 2385                 struct vnode **resultvp, uint32_t *vidp)
 2386 {
 2387         struct filedesc *fdp = p->p_fd;
 2388         struct fileproc *fp;
 2389 
 2390         proc_fdlock_spin(p);
 2391         if (fd < 0 || fd >= fdp->fd_nfiles ||
 2392                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2393                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2394                 proc_fdunlock(p);
 2395                 return (EBADF);
 2396         }
 2397         if (fp->f_type != DTYPE_VNODE) {
 2398                 proc_fdunlock(p);
 2399                 return(ENOTSUP);
 2400         }
 2401         fp->f_iocount++;
 2402 
 2403         if (resultfp)
 2404                 *resultfp = fp;
 2405         if (resultvp)
 2406                 *resultvp = (struct vnode *)fp->f_data;
 2407         if (vidp)
 2408                 *vidp = (uint32_t)vnode_vid((struct vnode *)fp->f_data);
 2409         proc_fdunlock(p);
 2410 
 2411         return (0);
 2412 }
 2413 
 2414 
 2415 /*
 2416  * fp_getfsock
 2417  *
 2418  * Description: Get fileproc and socket pointer for a given fd from the
 2419  *              per process open file table of the specified process, and if
 2420  *              successful, increment the f_iocount
 2421  *
 2422  * Parameters:  p                               Process in which fd lives
 2423  *              fd                              fd to get information for
 2424  *              resultfp                        Pointer to result fileproc
 2425  *                                              pointer area, or 0 if none
 2426  *              results                         Pointer to result socket
 2427  *                                              pointer area, or 0 if none
 2428  *
 2429  * Returns:     EBADF                   The file descriptor is invalid
 2430  *              EOPNOTSUPP              The file descriptor is not a socket
 2431  *              0                       Success
 2432  *
 2433  * Implicit returns:
 2434  *              *resultfp (modified)            Fileproc pointer
 2435  *              *results (modified)             socket pointer
 2436  *
 2437  * Notes:       EOPNOTSUPP should probably be ENOTSOCK; this function is only
 2438  *              ever called from accept1().
 2439  */
 2440 int
 2441 fp_getfsock(proc_t p, int fd, struct fileproc **resultfp,
 2442             struct socket **results)
 2443 {
 2444         struct filedesc *fdp = p->p_fd;
 2445         struct fileproc *fp;
 2446 
 2447         proc_fdlock_spin(p);
 2448         if (fd < 0 || fd >= fdp->fd_nfiles ||
 2449                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2450                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2451                 proc_fdunlock(p);
 2452                 return (EBADF);
 2453         }
 2454         if (fp->f_type != DTYPE_SOCKET) {
 2455                 proc_fdunlock(p);
 2456                 return(EOPNOTSUPP);
 2457         }
 2458         fp->f_iocount++;
 2459 
 2460         if (resultfp)
 2461                 *resultfp = fp;
 2462         if (results)
 2463                 *results = (struct socket *)fp->f_data;
 2464         proc_fdunlock(p);
 2465 
 2466         return (0);
 2467 }
 2468 
 2469 
 2470 /*
 2471  * fp_getfkq
 2472  *
 2473  * Description: Get fileproc and kqueue pointer for a given fd from the
 2474  *              per process open file table of the specified process, and if
 2475  *              successful, increment the f_iocount
 2476  *
 2477  * Parameters:  p                               Process in which fd lives
 2478  *              fd                              fd to get information for
 2479  *              resultfp                        Pointer to result fileproc
 2480  *                                              pointer area, or 0 if none
 2481  *              resultkq                        Pointer to result kqueue
 2482  *                                              pointer area, or 0 if none
 2483  *
 2484  * Returns:     EBADF                   The file descriptor is invalid
 2485  *              EBADF                   The file descriptor is not a socket
 2486  *              0                       Success
 2487  *
 2488  * Implicit returns:
 2489  *              *resultfp (modified)            Fileproc pointer
 2490  *              *resultkq (modified)            kqueue pointer
 2491  *
 2492  * Notes:       The second EBADF should probably be something else to make
 2493  *              the error condition distinct.
 2494  */
 2495 int
 2496 fp_getfkq(proc_t p, int fd, struct fileproc **resultfp,
 2497           struct kqueue **resultkq)
 2498 {
 2499         struct filedesc *fdp = p->p_fd;
 2500         struct fileproc *fp;
 2501 
 2502         proc_fdlock_spin(p);
 2503         if ( fd < 0 || fd >= fdp->fd_nfiles ||
 2504                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2505                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2506                 proc_fdunlock(p);
 2507                 return (EBADF);
 2508         }
 2509         if (fp->f_type != DTYPE_KQUEUE) {
 2510                 proc_fdunlock(p);
 2511                 return(EBADF);
 2512         }
 2513         fp->f_iocount++;
 2514 
 2515         if (resultfp)
 2516                 *resultfp = fp;
 2517         if (resultkq)
 2518                 *resultkq = (struct kqueue *)fp->f_data;
 2519         proc_fdunlock(p);
 2520 
 2521         return (0);
 2522 }
 2523 
 2524 
 2525 /*
 2526  * fp_getfpshm
 2527  *
 2528  * Description: Get fileproc and POSIX shared memory pointer for a given fd
 2529  *              from the per process open file table of the specified process
 2530  *              and if successful, increment the f_iocount
 2531  *
 2532  * Parameters:  p                               Process in which fd lives
 2533  *              fd                              fd to get information for
 2534  *              resultfp                        Pointer to result fileproc
 2535  *                                              pointer area, or 0 if none
 2536  *              resultpshm                      Pointer to result POSIX
 2537  *                                              shared memory pointer
 2538  *                                              pointer area, or 0 if none
 2539  *
 2540  * Returns:     EBADF                   The file descriptor is invalid
 2541  *              EBADF                   The file descriptor is not a POSIX
 2542  *                                      shared memory area
 2543  *              0                       Success
 2544  *
 2545  * Implicit returns:
 2546  *              *resultfp (modified)            Fileproc pointer
 2547  *              *resultpshm (modified)          POSIX shared memory pointer
 2548  *
 2549  * Notes:       The second EBADF should probably be something else to make
 2550  *              the error condition distinct.
 2551  */
 2552 int
 2553 fp_getfpshm(proc_t p, int fd, struct fileproc **resultfp,
 2554             struct pshmnode **resultpshm)
 2555 {
 2556         struct filedesc *fdp = p->p_fd;
 2557         struct fileproc *fp;
 2558 
 2559         proc_fdlock_spin(p);
 2560         if (fd < 0 || fd >= fdp->fd_nfiles ||
 2561                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2562                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2563                 proc_fdunlock(p);
 2564                 return (EBADF);
 2565         }
 2566         if (fp->f_type != DTYPE_PSXSHM) {
 2567 
 2568                 proc_fdunlock(p);
 2569                 return(EBADF);
 2570         }
 2571         fp->f_iocount++;
 2572 
 2573         if (resultfp)
 2574                 *resultfp = fp;
 2575         if (resultpshm)
 2576                 *resultpshm = (struct pshmnode *)fp->f_data;
 2577         proc_fdunlock(p);
 2578 
 2579         return (0);
 2580 }
 2581 
 2582 
 2583 /*
 2584  * fp_getfsem
 2585  *
 2586  * Description: Get fileproc and POSIX semaphore pointer for a given fd from
 2587  *              the per process open file table of the specified process
 2588  *              and if successful, increment the f_iocount
 2589  *
 2590  * Parameters:  p                               Process in which fd lives
 2591  *              fd                              fd to get information for
 2592  *              resultfp                        Pointer to result fileproc
 2593  *                                              pointer area, or 0 if none
 2594  *              resultpsem                      Pointer to result POSIX
 2595  *                                              semaphore pointer area, or
 2596  *                                              0 if none
 2597  *
 2598  * Returns:     EBADF                   The file descriptor is invalid
 2599  *              EBADF                   The file descriptor is not a POSIX
 2600  *                                      semaphore
 2601  *              0                       Success
 2602  *
 2603  * Implicit returns:
 2604  *              *resultfp (modified)            Fileproc pointer
 2605  *              *resultpsem (modified)          POSIX semaphore pointer
 2606  *
 2607  * Notes:       The second EBADF should probably be something else to make
 2608  *              the error condition distinct.
 2609  *
 2610  *              In order to support unnamed POSIX semaphores, the named
 2611  *              POSIX semaphores will have to move out of the per-process
 2612  *              open filetable, and into a global table that is shared with
 2613  *              unnamed POSIX semaphores, since unnamed POSIX semaphores
 2614  *              are typically used by declaring instances in shared memory,
 2615  *              and there's no other way to do this without changing the
 2616  *              underlying type, which would introduce binary compatibility
 2617  *              issues.
 2618  */
 2619 int
 2620 fp_getfpsem(proc_t p, int fd, struct fileproc **resultfp,
 2621             struct psemnode **resultpsem)
 2622 {
 2623         struct filedesc *fdp = p->p_fd;
 2624         struct fileproc *fp;
 2625 
 2626         proc_fdlock_spin(p);
 2627         if (fd < 0 || fd >= fdp->fd_nfiles ||
 2628                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2629                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2630                 proc_fdunlock(p);
 2631                 return (EBADF);
 2632         }
 2633         if (fp->f_type != DTYPE_PSXSEM) {
 2634                 proc_fdunlock(p);
 2635                 return(EBADF);
 2636         }
 2637         fp->f_iocount++;
 2638 
 2639         if (resultfp)
 2640                 *resultfp = fp;
 2641         if (resultpsem)
 2642                 *resultpsem = (struct psemnode *)fp->f_data;
 2643         proc_fdunlock(p);
 2644 
 2645         return (0);
 2646 }
 2647 
 2648 
 2649 /*
 2650  * fp_getfpipe
 2651  *
 2652  * Description: Get fileproc and pipe pointer for a given fd from the
 2653  *              per process open file table of the specified process
 2654  *              and if successful, increment the f_iocount
 2655  *
 2656  * Parameters:  p                               Process in which fd lives
 2657  *              fd                              fd to get information for
 2658  *              resultfp                        Pointer to result fileproc
 2659  *                                              pointer area, or 0 if none
 2660  *              resultpipe                      Pointer to result pipe
 2661  *                                              pointer area, or 0 if none
 2662  *
 2663  * Returns:     EBADF                   The file descriptor is invalid
 2664  *              EBADF                   The file descriptor is not a socket
 2665  *              0                       Success
 2666  *
 2667  * Implicit returns:
 2668  *              *resultfp (modified)            Fileproc pointer
 2669  *              *resultpipe (modified)          pipe pointer
 2670  *
 2671  * Notes:       The second EBADF should probably be something else to make
 2672  *              the error condition distinct.
 2673  */
 2674 int
 2675 fp_getfpipe(proc_t p, int fd, struct fileproc **resultfp,
 2676             struct pipe **resultpipe)
 2677 {
 2678         struct filedesc *fdp = p->p_fd;
 2679         struct fileproc *fp;
 2680 
 2681         proc_fdlock_spin(p);
 2682         if (fd < 0 || fd >= fdp->fd_nfiles ||
 2683                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2684                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2685                 proc_fdunlock(p);
 2686                 return (EBADF);
 2687         }
 2688         if (fp->f_type != DTYPE_PIPE) {
 2689                 proc_fdunlock(p);
 2690                 return(EBADF);
 2691         }
 2692         fp->f_iocount++;
 2693 
 2694         if (resultfp)
 2695                 *resultfp = fp;
 2696         if (resultpipe)
 2697                 *resultpipe = (struct pipe *)fp->f_data;
 2698         proc_fdunlock(p);
 2699 
 2700         return (0);
 2701 }
 2702 
 2703 
 2704 #define DTYPE_ATALK -1          /* XXX This does not belong here */
 2705 
 2706 
 2707 /*
 2708  * fp_getfatalk
 2709  *
 2710  * Description: Get fileproc and atalk pointer for a given fd from the
 2711  *              per process open file table of the specified process
 2712  *              and if successful, increment the f_iocount
 2713  *
 2714  * Parameters:  p                               Process in which fd lives
 2715  *              fd                              fd to get information for
 2716  *              resultfp                        Pointer to result fileproc
 2717  *                                              pointer area, or 0 if none
 2718  *              resultatalk                     Pointer to result atalk
 2719  *                                              pointer area, or 0 if none
 2720  * Returns:     EBADF                   The file descriptor is invalid
 2721  *              EBADF                   The file descriptor is not a socket
 2722  *              0                       Success
 2723  *
 2724  * Implicit returns:
 2725  *              *resultfp (modified)            Fileproc pointer
 2726  *              *resultatalk (modified)         atalk pointer
 2727  *
 2728  * Notes:       The second EBADF should probably be something else to make
 2729  *              the error condition distinct.
 2730  *
 2731  *              XXX This code is specific to AppleTalk protocol support, and
 2732  *              XXX should be conditionally compiled
 2733  */
 2734 int
 2735 fp_getfatalk(proc_t p, int fd, struct fileproc **resultfp,
 2736              struct atalk **resultatalk)
 2737 {
 2738         struct filedesc *fdp = p->p_fd;
 2739         struct fileproc *fp;
 2740 
 2741         proc_fdlock_spin(p);
 2742         if (fd < 0 || fd >= fdp->fd_nfiles ||
 2743                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2744                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2745                 proc_fdunlock(p);
 2746                 return (EBADF);
 2747         }
 2748         if (fp->f_type != (DTYPE_ATALK+1)) {
 2749                 proc_fdunlock(p);
 2750                 return(EBADF);
 2751         }
 2752         fp->f_iocount++;
 2753 
 2754         if (resultfp)
 2755                 *resultfp = fp;
 2756         if (resultatalk)
 2757                 *resultatalk = (struct atalk *)fp->f_data;
 2758         proc_fdunlock(p);
 2759 
 2760         return (0);
 2761 }
 2762 
 2763 
 2764 /*
 2765  * fp_lookup
 2766  *
 2767  * Description: Get fileproc pointer for a given fd from the per process
 2768  *              open file table of the specified process and if successful,
 2769  *              increment the f_iocount
 2770  *
 2771  * Parameters:  p                               Process in which fd lives
 2772  *              fd                              fd to get information for
 2773  *              resultfp                        Pointer to result fileproc
 2774  *                                              pointer area, or 0 if none
 2775  *              locked                          !0 if the caller holds the
 2776  *                                              proc_fdlock, 0 otherwise
 2777  *
 2778  * Returns:     0                       Success
 2779  *              EBADF                   Bad file descriptor
 2780  *
 2781  * Implicit returns:
 2782  *              *resultfp (modified)            Fileproc pointer
 2783  *
 2784  * Locks:       If the argument 'locked' is non-zero, then the caller is
 2785  *              expected to have taken and held the proc_fdlock; if it is
 2786  *              zero, than this routine internally takes and drops this lock.
 2787  */
 2788 int
 2789 fp_lookup(proc_t p, int fd, struct fileproc **resultfp, int locked)
 2790 {
 2791         struct filedesc *fdp = p->p_fd;
 2792         struct fileproc *fp;
 2793 
 2794         if (!locked)
 2795                 proc_fdlock_spin(p);
 2796         if (fd < 0 || fdp == NULL || fd >= fdp->fd_nfiles ||
 2797                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2798                         (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
 2799                 if (!locked)
 2800                         proc_fdunlock(p);
 2801                 return (EBADF);
 2802         }
 2803         fp->f_iocount++;
 2804 
 2805         if (resultfp)
 2806                 *resultfp = fp;
 2807         if (!locked)
 2808                 proc_fdunlock(p);
 2809                 
 2810         return (0);
 2811 }
 2812 
 2813 
 2814 /*
 2815  * fp_drop_written
 2816  *
 2817  * Description: Set the FP_WRITTEN flag on the fileproc and drop the I/O
 2818  *              reference previously taken by calling fp_lookup et. al.
 2819  *
 2820  * Parameters:  p                               Process in which the fd lives
 2821  *              fd                              fd associated with the fileproc
 2822  *              fp                              fileproc on which to set the
 2823  *                                              flag and drop the reference
 2824  *
 2825  * Returns:     0                               Success
 2826  *      fp_drop:EBADF                           Bad file descriptor
 2827  *
 2828  * Locks:       This function internally takes and drops the proc_fdlock for
 2829  *              the supplied process
 2830  *
 2831  * Notes:       The fileproc must correspond to the fd in the supplied proc
 2832  */
 2833 int
 2834 fp_drop_written(proc_t p, int fd, struct fileproc *fp)
 2835 {
 2836         int error;
 2837 
 2838         proc_fdlock_spin(p);
 2839 
 2840         fp->f_flags |= FP_WRITTEN;
 2841         
 2842         error = fp_drop(p, fd, fp, 1);
 2843 
 2844         proc_fdunlock(p);
 2845                 
 2846         return (error);
 2847 }
 2848 
 2849 
 2850 /*
 2851  * fp_drop_event
 2852  *
 2853  * Description: Set the FP_WAITEVENT flag on the fileproc and drop the I/O
 2854  *              reference previously taken by calling fp_lookup et. al.
 2855  *
 2856  * Parameters:  p                               Process in which the fd lives
 2857  *              fd                              fd associated with the fileproc
 2858  *              fp                              fileproc on which to set the
 2859  *                                              flag and drop the reference
 2860  *
 2861  * Returns:     0                               Success
 2862  *      fp_drop:EBADF                           Bad file descriptor
 2863  *
 2864  * Locks:       This function internally takes and drops the proc_fdlock for
 2865  *              the supplied process
 2866  *
 2867  * Notes:       The fileproc must correspond to the fd in the supplied proc
 2868  */
 2869 int
 2870 fp_drop_event(proc_t p, int fd, struct fileproc *fp)
 2871 {
 2872         int error;
 2873 
 2874         proc_fdlock_spin(p);
 2875 
 2876         fp->f_flags |= FP_WAITEVENT;
 2877         
 2878         error = fp_drop(p, fd, fp, 1);
 2879 
 2880         proc_fdunlock(p);
 2881                 
 2882         return (error);
 2883 }
 2884 
 2885 
 2886 /*
 2887  * fp_drop
 2888  *
 2889  * Description: Drop the I/O reference previously taken by calling fp_lookup
 2890  *              et. al.
 2891  *
 2892  * Parameters:  p                               Process in which the fd lives
 2893  *              fd                              fd associated with the fileproc
 2894  *              fp                              fileproc on which to set the
 2895  *                                              flag and drop the reference
 2896  *              locked                          flag to internally take and
 2897  *                                              drop proc_fdlock if it is not
 2898  *                                              already held by the caller
 2899  *
 2900  * Returns:     0                               Success
 2901  *              EBADF                           Bad file descriptor
 2902  *
 2903  * Locks:       This function internally takes and drops the proc_fdlock for
 2904  *              the supplied process if 'locked' is non-zero, and assumes that
 2905  *              the caller already holds this lock if 'locked' is non-zero.
 2906  *
 2907  * Notes:       The fileproc must correspond to the fd in the supplied proc
 2908  */
 2909 int
 2910 fp_drop(proc_t p, int fd, struct fileproc *fp, int locked)
 2911 {
 2912         struct filedesc *fdp = p->p_fd;
 2913         int     needwakeup = 0;
 2914 
 2915         if (!locked)
 2916                 proc_fdlock_spin(p);
 2917          if ((fp == FILEPROC_NULL) && (fd < 0 || fd >= fdp->fd_nfiles ||
 2918                         (fp = fdp->fd_ofiles[fd]) == NULL ||
 2919                         ((fdp->fd_ofileflags[fd] & UF_RESERVED) &&
 2920                          !(fdp->fd_ofileflags[fd] & UF_CLOSING)))) {
 2921                 if (!locked)
 2922                         proc_fdunlock(p);
 2923                 return (EBADF);
 2924         }
 2925         fp->f_iocount--;
 2926 
 2927         if (p->p_fpdrainwait && fp->f_iocount == 0) {
 2928                 p->p_fpdrainwait = 0;
 2929                 needwakeup = 1;
 2930         }
 2931         if (!locked)
 2932                 proc_fdunlock(p);
 2933         if (needwakeup)
 2934                 wakeup(&p->p_fpdrainwait);
 2935                 
 2936         return (0);
 2937 }
 2938 
 2939 
 2940 /*
 2941  * file_vnode
 2942  *
 2943  * Description: Given an fd, look it up in the current process's per process
 2944  *              open file table, and return its internal vnode pointer.
 2945  *
 2946  * Parameters:  fd                              fd to obtain vnode from
 2947  *              vpp                             pointer to vnode return area
 2948  *
 2949  * Returns:     0                               Success
 2950  *              EINVAL                          The fd does not refer to a
 2951  *                                              vnode fileproc entry
 2952  *      fp_lookup:EBADF                         Bad file descriptor
 2953  *
 2954  * Implicit returns:
 2955  *              *vpp (modified)                 Returned vnode pointer
 2956  *
 2957  * Locks:       This function internally takes and drops the proc_fdlock for
 2958  *              the current process
 2959  *
 2960  * Notes:       If successful, this function increments the f_iocount on the
 2961  *              fd's corresponding fileproc.
 2962  *
 2963  *              The fileproc referenced is not returned; because of this, care
 2964  *              must be taken to not drop the last reference (e.g. by closing
 2965  *              the file).  This is inhernely unsafe, since the reference may
 2966  *              not be recoverable from the vnode, if there is a subsequent
 2967  *              close that destroys the associate fileproc.  The caller should
 2968  *              therefore retain their own reference on the fileproc so that
 2969  *              the f_iocount can be dropped subsequently.  Failure to do this
 2970  *              can result in the returned pointer immediately becoming invalid
 2971  *              following the call.
 2972  *
 2973  *              Use of this function is discouraged.
 2974  */
 2975 int
 2976 file_vnode(int fd, struct vnode **vpp)
 2977 {
 2978         proc_t p = current_proc();
 2979         struct fileproc *fp;
 2980         int error;
 2981         
 2982         proc_fdlock_spin(p);
 2983         if ( (error = fp_lookup(p, fd, &fp, 1)) ) {
 2984                 proc_fdunlock(p);
 2985                 return(error);
 2986         }
 2987         if (fp->f_type != DTYPE_VNODE) {
 2988                 fp_drop(p, fd, fp,1);
 2989                 proc_fdunlock(p);
 2990                 return(EINVAL);
 2991         }
 2992         *vpp = (struct vnode *)fp->f_data;
 2993         proc_fdunlock(p);
 2994 
 2995         return(0);
 2996 }
 2997 
 2998 
 2999 /*
 3000  * file_socket
 3001  *
 3002  * Description: Given an fd, look it up in the current process's per process
 3003  *              open file table, and return its internal socket pointer.
 3004  *
 3005  * Parameters:  fd                              fd to obtain vnode from
 3006  *              sp                              pointer to socket return area
 3007  *
 3008  * Returns:     0                               Success
 3009  *              ENOTSOCK                        Not a socket
 3010  *              fp_lookup:EBADF                 Bad file descriptor
 3011  *
 3012  * Implicit returns:
 3013  *              *sp (modified)                  Returned socket pointer
 3014  *
 3015  * Locks:       This function internally takes and drops the proc_fdlock for
 3016  *              the current process
 3017  *
 3018  * Notes:       If successful, this function increments the f_iocount on the
 3019  *              fd's corresponding fileproc.
 3020  *
 3021  *              The fileproc referenced is not returned; because of this, care
 3022  *              must be taken to not drop the last reference (e.g. by closing
 3023  *              the file).  This is inhernely unsafe, since the reference may
 3024  *              not be recoverable from the socket, if there is a subsequent
 3025  *              close that destroys the associate fileproc.  The caller should
 3026  *              therefore retain their own reference on the fileproc so that
 3027  *              the f_iocount can be dropped subsequently.  Failure to do this
 3028  *              can result in the returned pointer immediately becoming invalid
 3029  *              following the call.
 3030  *
 3031  *              Use of this function is discouraged.
 3032  */
 3033 int
 3034 file_socket(int fd, struct socket **sp)
 3035 {
 3036         proc_t p = current_proc();
 3037         struct fileproc *fp;
 3038         int error;
 3039         
 3040         proc_fdlock_spin(p);
 3041         if ( (error = fp_lookup(p, fd, &fp, 1)) ) {
 3042                 proc_fdunlock(p);
 3043                 return(error);
 3044         }
 3045         if (fp->f_type != DTYPE_SOCKET) {
 3046                 fp_drop(p, fd, fp,1);
 3047                 proc_fdunlock(p);
 3048                 return(ENOTSOCK);
 3049         }
 3050         *sp = (struct socket *)fp->f_data;
 3051         proc_fdunlock(p);
 3052 
 3053         return(0);
 3054 }
 3055 
 3056 
 3057 /*
 3058  * file_flags
 3059  *
 3060  * Description: Given an fd, look it up in the current process's per process
 3061  *              open file table, and return its fileproc's flags field.
 3062  *
 3063  * Parameters:  fd                              fd whose flags are to be
 3064  *                                              retrieved
 3065  *              flags                           pointer to flags data area
 3066  *
 3067  * Returns:     0                               Success
 3068  *              ENOTSOCK                        Not a socket
 3069  *              fp_lookup:EBADF                 Bad file descriptor
 3070  *
 3071  * Implicit returns:
 3072  *              *flags (modified)               Returned flags field
 3073  *
 3074  * Locks:       This function internally takes and drops the proc_fdlock for
 3075  *              the current process
 3076  *
 3077  * Notes:       This function will internally increment and decrement the
 3078  *              f_iocount of the fileproc as part of its operation.
 3079  */
 3080 int
 3081 file_flags(int fd, int *flags)
 3082 {
 3083 
 3084         proc_t p = current_proc();
 3085         struct fileproc *fp;
 3086         int error;
 3087         
 3088         proc_fdlock_spin(p);
 3089         if ( (error = fp_lookup(p, fd, &fp, 1)) ) {
 3090                 proc_fdunlock(p);
 3091                 return(error);
 3092         }
 3093         *flags = (int)fp->f_flag;
 3094         fp_drop(p, fd, fp,1);
 3095         proc_fdunlock(p);
 3096 
 3097         return(0);
 3098 }
 3099 
 3100 
 3101 /*
 3102  * file_drop
 3103  *
 3104  * Description: Drop an iocount reference on an fd, and wake up any waiters
 3105  *              for draining (i.e. blocked in fileproc_drain() called during
 3106  *              the last attempt to close a file).
 3107  *
 3108  * Parameters:  fd                              fd on which an ioreference is
 3109  *                                              to be dropped
 3110  *
 3111  * Returns:     0                               Success
 3112  *              EBADF                           Bad file descriptor
 3113  *
 3114  * Description: Given an fd, look it up in the current process's per process
 3115  *              open file table, and drop it's fileproc's f_iocount by one
 3116  *
 3117  * Notes:       This is intended as a corresponding operation to the functions
 3118  *              file_vnode() and file_socket() operations.
 3119  *
 3120  *              Technically, the close reference is supposed to be protected
 3121  *              by a fileproc_drain(), however, a drain will only block if
 3122  *              the fd refers to a character device, and that device has had
 3123  *              preparefileread() called on it.  If it refers to something
 3124  *              other than a character device, then the drain will occur and
 3125  *              block each close attempt, rather than merely the last close.
 3126  *
 3127  *              Since it's possible for an fd that refers to a character
 3128  *              device to have an intermediate close followed by an open to
 3129  *              cause a different file to correspond to that descriptor,
 3130  *              unless there was a cautionary reference taken on the fileproc,
 3131  *              this is an inherently unsafe function.  This happens in the
 3132  *              case where multiple fd's in a process refer to the same
 3133  *              character device (e.g. stdin/out/err pointing to a tty, etc.).
 3134  *
 3135  *              Use of this function is discouraged.
 3136  */
 3137 int 
 3138 file_drop(int fd)
 3139 {
 3140         struct fileproc *fp;
 3141         proc_t p = current_proc();
 3142         int     needwakeup = 0;
 3143 
 3144         proc_fdlock_spin(p);
 3145         if (fd < 0 || fd >= p->p_fd->fd_nfiles ||
 3146                         (fp = p->p_fd->fd_ofiles[fd]) == NULL ||
 3147                         ((p->p_fd->fd_ofileflags[fd] & UF_RESERVED) &&
 3148                          !(p->p_fd->fd_ofileflags[fd] & UF_CLOSING))) {
 3149                 proc_fdunlock(p);
 3150                 return (EBADF);
 3151         }
 3152         fp->f_iocount --;
 3153 
 3154         if (p->p_fpdrainwait && fp->f_iocount == 0) {
 3155                 p->p_fpdrainwait = 0;
 3156                 needwakeup = 1;
 3157         }
 3158         proc_fdunlock(p);
 3159 
 3160         if (needwakeup)
 3161                 wakeup(&p->p_fpdrainwait);
 3162         return(0);
 3163 }
 3164 
 3165 
 3166 /*
 3167  * falloc
 3168  *
 3169  * Description: Allocate an entry in the per process open file table and
 3170  *              return the corresponding fileproc and fd.
 3171  *
 3172  * Parameters:  p                               The process in whose open file
 3173  *                                              table the fd is to be allocated
 3174  *              resultfp                        Pointer to fileproc pointer
 3175  *                                              return area
 3176  *              resultfd                        Pointer to fd return area
 3177  *              ctx                             VFS context
 3178  *
 3179  * Returns:     0                               Success
 3180  *      falloc:ENFILE                           Too many open files in system
 3181  *      falloc:EMFILE                           Too many open files in process
 3182  *      falloc:ENOMEM                           M_FILEPROC or M_FILEGLOB zone
 3183  *                                              exhausted
 3184  *
 3185  * Implicit returns:
 3186  *              *resultfd (modified)            Returned fileproc pointer
 3187  *              *resultfd (modified)            Returned fd
 3188  *
 3189  * Locks:       This function takes and drops the proc_fdlock; if this lock
 3190  *              is alread held, use falloc_locked() instead.
 3191  *
 3192  * Notes:       This function takes separate process and context arguments
 3193  *              solely to support kern_exec.c; otherwise, it would take
 3194  *              neither, and expect falloc_locked() to use the
 3195  *              vfs_context_current() routine internally.
 3196  */
 3197 int
 3198 falloc(proc_t p, struct fileproc **resultfp, int *resultfd, vfs_context_t ctx)
 3199 {
 3200         int error;
 3201 
 3202         proc_fdlock(p);
 3203         error = falloc_locked(p, resultfp, resultfd, ctx, 1);
 3204         proc_fdunlock(p);
 3205 
 3206         return(error);
 3207 }
 3208 
 3209 
 3210 /*
 3211  * falloc_locked
 3212  *
 3213  * Create a new open file structure and allocate
 3214  * a file decriptor for the process that refers to it.
 3215  *
 3216  * Returns:     0                       Success
 3217  *
 3218  * Description: Allocate an entry in the per process open file table and
 3219  *              return the corresponding fileproc and fd.
 3220  *
 3221  * Parameters:  p                               The process in whose open file
 3222  *                                              table the fd is to be allocated
 3223  *              resultfp                        Pointer to fileproc pointer
 3224  *                                              return area
 3225  *              resultfd                        Pointer to fd return area
 3226  *              ctx                             VFS context
 3227  *              locked                          Flag to indicate whether the
 3228  *                                              caller holds proc_fdlock
 3229  *
 3230  * Returns:     0                               Success
 3231  *              ENFILE                          Too many open files in system
 3232  *              fdalloc:EMFILE                  Too many open files in process
 3233  *              ENOMEM                          M_FILEPROC or M_FILEGLOB zone
 3234  *                                              exhausted
 3235  *      fdalloc:ENOMEM
 3236  *
 3237  * Implicit returns:
 3238  *              *resultfd (modified)            Returned fileproc pointer
 3239  *              *resultfd (modified)            Returned fd
 3240  *
 3241  * Locks:       If the parameter 'locked' is zero, this function takes and
 3242  *              drops the proc_fdlock; if non-zero, the caller must hold the
 3243  *              lock.
 3244  *
 3245  * Notes:       If you intend to use a non-zero 'locked' parameter, use the
 3246  *              utility function falloc() instead.
 3247  *
 3248  *              This function takes separate process and context arguments
 3249  *              solely to support kern_exec.c; otherwise, it would take
 3250  *              neither, and use the vfs_context_current() routine internally.
 3251  */
 3252 int
 3253 falloc_locked(proc_t p, struct fileproc **resultfp, int *resultfd,
 3254               vfs_context_t ctx, int locked)
 3255 {
 3256         struct fileproc *fp, *fq;
 3257         struct fileglob *fg;
 3258         int error, nfd;
 3259 
 3260         if (!locked)
 3261                 proc_fdlock(p);
 3262         if ( (error = fdalloc(p, 0, &nfd)) ) {
 3263                 if (!locked)
 3264                         proc_fdunlock(p);
 3265                 return (error);
 3266         }
 3267         if (nfiles >= maxfiles) {
 3268                 if (!locked)
 3269                         proc_fdunlock(p);
 3270                 tablefull("file");
 3271                 return (ENFILE);
 3272         }
 3273 #if CONFIG_MACF
 3274         error = mac_file_check_create(proc_ucred(p));
 3275         if (error) {
 3276                 if (!locked)
 3277                         proc_fdunlock(p);
 3278                 return (error);
 3279         }
 3280 #endif
 3281 
 3282         /*
 3283          * Allocate a new file descriptor.
 3284          * If the process has file descriptor zero open, add to the list
 3285          * of open files at that point, otherwise put it at the front of
 3286          * the list of open files.
 3287          */
 3288         proc_fdunlock(p);
 3289 
 3290         MALLOC_ZONE(fp, struct fileproc *, sizeof(struct fileproc), M_FILEPROC, M_WAITOK);
 3291         if (fp == NULL) {
 3292                 if (locked)
 3293                         proc_fdlock(p);
 3294                 return (ENOMEM);
 3295         }
 3296         MALLOC_ZONE(fg, struct fileglob *, sizeof(struct fileglob), M_FILEGLOB, M_WAITOK);
 3297         if (fg == NULL) {
 3298                 FREE_ZONE(fp, sizeof(*fp), M_FILEPROC);
 3299                 if (locked)
 3300                         proc_fdlock(p);
 3301                 return (ENOMEM);
 3302         }
 3303         bzero(fp, sizeof(struct fileproc));
 3304         bzero(fg, sizeof(struct fileglob));
 3305         lck_mtx_init(&fg->fg_lock, file_lck_grp, file_lck_attr);
 3306 
 3307         fp->f_iocount = 1;
 3308         fg->fg_count = 1;
 3309         fp->f_fglob = fg;
 3310 #if CONFIG_MACF
 3311         mac_file_label_init(fg);
 3312 #endif
 3313 
 3314         kauth_cred_ref(ctx->vc_ucred);
 3315 
 3316         proc_fdlock(p);
 3317 
 3318         fp->f_cred = ctx->vc_ucred;
 3319 
 3320 #if CONFIG_MACF
 3321         mac_file_label_associate(fp->f_cred, fg);
 3322 #endif
 3323 
 3324         lck_mtx_lock_spin(file_flist_lock);
 3325 
 3326         nfiles++;
 3327 
 3328         if ( (fq = p->p_fd->fd_ofiles[0]) ) {
 3329                 LIST_INSERT_AFTER(fq->f_fglob, fg, f_list);
 3330         } else {
 3331                 LIST_INSERT_HEAD(&filehead, fg, f_list);
 3332         }
 3333         lck_mtx_unlock(file_flist_lock);
 3334 
 3335         p->p_fd->fd_ofiles[nfd] = fp;
 3336 
 3337         if (!locked)
 3338                 proc_fdunlock(p);
 3339 
 3340         if (resultfp)
 3341                 *resultfp = fp;
 3342         if (resultfd)
 3343                 *resultfd = nfd;
 3344 
 3345         return (0);
 3346 }
 3347 
 3348 
 3349 /*
 3350  * fg_free
 3351  *
 3352  * Description: Free a file structure; drop the global open file count, and
 3353  *              drop the credential reference, if the fileglob has one, and
 3354  *              destroy the instance mutex before freeing
 3355  *
 3356  * Parameters:  fg                              Pointer to fileglob to be
 3357  *                                              freed
 3358  *
 3359  * Returns:     void
 3360  */
 3361 void
 3362 fg_free(struct fileglob *fg)
 3363 {
 3364         lck_mtx_lock_spin(file_flist_lock);
 3365         LIST_REMOVE(fg, f_list);
 3366         nfiles--;
 3367         lck_mtx_unlock(file_flist_lock);
 3368 
 3369         if (IS_VALID_CRED(fg->fg_cred)) {
 3370                 kauth_cred_unref(&fg->fg_cred);
 3371         }
 3372         lck_mtx_destroy(&fg->fg_lock, file_lck_grp);
 3373 
 3374 #if CONFIG_MACF
 3375         mac_file_label_destroy(fg);
 3376 #endif
 3377         FREE_ZONE(fg, sizeof *fg, M_FILEGLOB);
 3378 }
 3379 
 3380 
 3381 /*
 3382  * fdexec
 3383  *
 3384  * Description: Perform close-on-exec processing for all files in a process
 3385  *              that are either marked as close-on-exec, or which were in the
 3386  *              process of being opened at the time of the execve
 3387  *
 3388  * Parameters:  p                               Pointer to process calling
 3389  *                                              execve
 3390  *
 3391  * Returns:     void
 3392  *
 3393  * Locks:       This function internally takes and drops proc_fdlock()
 3394  *
 3395  * Notes:       This function drops and retakes the kernel funnel; this is
 3396  *              inherently unsafe, since another thread may have the
 3397  *              proc_fdlock.
 3398  *
 3399  * XXX:         We should likely reverse the lock and funnel drop/acquire
 3400  *              order to avoid the small race window; it's also possible that
 3401  *              if the program doing the exec has an outstanding listen socket
 3402  *              and a network connection is completed asyncrhonously that we
 3403  *              will end up with a "ghost" socket reference in the new process.
 3404  *
 3405  *              This needs reworking to make it safe to remove the funnel from
 3406  *              the execve and posix_spawn system calls.
 3407  */
 3408 void
 3409 fdexec(proc_t p)
 3410 {
 3411         struct filedesc *fdp = p->p_fd;
 3412         int i = fdp->fd_lastfile;
 3413         struct fileproc *fp;
 3414 
 3415         proc_fdlock(p);
 3416         while (i >= 0) {
 3417 
 3418                 fp = fdp->fd_ofiles[i];
 3419                 if (
 3420                     ((fdp->fd_ofileflags[i] & (UF_RESERVED|UF_EXCLOSE)) == UF_EXCLOSE)
 3421 #if CONFIG_MACF
 3422                     || (fp && mac_file_check_inherit(proc_ucred(p), fp->f_fglob))
 3423 #endif
 3424                 ) {
 3425                         if (i < fdp->fd_knlistsize)
 3426                                 knote_fdclose(p, i);
 3427                         procfdtbl_clearfd(p, i);
 3428                         if (i == fdp->fd_lastfile && i > 0)
 3429                                 fdp->fd_lastfile--;
 3430                         if (i < fdp->fd_freefile)
 3431                                 fdp->fd_freefile = i;
 3432                         closef_locked(fp, fp->f_fglob, p);
 3433                         FREE_ZONE(fp, sizeof(*fp), M_FILEPROC);
 3434                 }
 3435                 i--;
 3436         }
 3437         proc_fdunlock(p);
 3438 }
 3439 
 3440 
 3441 /*
 3442  * fdcopy
 3443  *
 3444  * Description: Copy a filedesc structure.  This is normally used as part of
 3445  *              forkproc() when forking a new process, to copy the per process
 3446  *              open file table over to the new process.
 3447  *
 3448  * Parameters:  p                               Process whose open file table
 3449  *                                              is to be copied (parent)
 3450  *              uth_cdir                        Per thread current working
 3451  *                                              cirectory, or NULL
 3452  *
 3453  * Returns:     NULL                            Copy failed
 3454  *              !NULL                           Pointer to new struct filedesc
 3455  *
 3456  * Locks:       This function internally takes and drops proc_fdlock()
 3457  *
 3458  * Notes:       Files are copied directly, ignoring the new resource limits
 3459  *              for the process that's being copied into.  Since the descriptor
 3460  *              references are just additional references, this does not count
 3461  *              against the number of open files on the system.
 3462  *
 3463  *              The struct filedesc includes the current working directory,
 3464  *              and the current root directory, if the process is chroot'ed.
 3465  *
 3466  *              If the exec was called by a thread using a per thread current
 3467  *              working directory, we inherit the working directory from the
 3468  *              thread making the call, rather than from the process.
 3469  *
 3470  *              In the case of a failure to obtain a reference, for most cases,
 3471  *              the file entry will be silently droppped.  There's an exception
 3472  *              for the case of a chroot dir, since a failure to to obtain a
 3473  *              reference there would constitute an "escape" from the chroot
 3474  *              environment, which must not be allowed.  In that case, we will
 3475  *              deny the execve() operation, rather than allowing the escape.
 3476  */
 3477 struct filedesc *
 3478 fdcopy(proc_t p, vnode_t uth_cdir)
 3479 {
 3480         struct filedesc *newfdp, *fdp = p->p_fd;
 3481         int i;
 3482         struct fileproc *ofp, *fp;
 3483         vnode_t v_dir;
 3484 
 3485         MALLOC_ZONE(newfdp, struct filedesc *,
 3486                         sizeof(*newfdp), M_FILEDESC, M_WAITOK);
 3487         if (newfdp == NULL)
 3488                 return(NULL);
 3489 
 3490         proc_fdlock(p);
 3491 
 3492         /*
 3493          * the FD_CHROOT flag will be inherited via this copy
 3494          */
 3495         (void) memcpy(newfdp, fdp, sizeof(*newfdp));
 3496 
 3497         /*
 3498          * If we are running with per-thread current working directories,
 3499          * inherit the new current working directory from the current thread
 3500          * instead, before we take our references.
 3501          */
 3502         if (uth_cdir != NULLVP)
 3503                 newfdp->fd_cdir = uth_cdir;
 3504 
 3505         /*
 3506          * For both fd_cdir and fd_rdir make sure we get
 3507          * a valid reference... if we can't, than set
 3508          * set the pointer(s) to NULL in the child... this
 3509          * will keep us from using a non-referenced vp
 3510          * and allows us to do the vnode_rele only on
 3511          * a properly referenced vp
 3512          */
 3513         if ( (v_dir = newfdp->fd_cdir) ) {
 3514                 if (vnode_getwithref(v_dir) == 0) {
 3515                         if ( (vnode_ref(v_dir)) )
 3516                                 newfdp->fd_cdir = NULL;
 3517                         vnode_put(v_dir);
 3518                 } else
 3519                         newfdp->fd_cdir = NULL;
 3520         }
 3521         if (newfdp->fd_cdir == NULL && fdp->fd_cdir) {
 3522                 /*
 3523                  * we couldn't get a new reference on
 3524                  * the current working directory being
 3525                  * inherited... we might as well drop
 3526                  * our reference from the parent also
 3527                  * since the vnode has gone DEAD making
 3528                  * it useless... by dropping it we'll
 3529                  * be that much closer to recyling it
 3530                  */
 3531                 vnode_rele(fdp->fd_cdir);
 3532                 fdp->fd_cdir = NULL;
 3533         }
 3534 
 3535         if ( (v_dir = newfdp->fd_rdir) ) {
 3536                 if (vnode_getwithref(v_dir) == 0) {
 3537                         if ( (vnode_ref(v_dir)) )
 3538                                 newfdp->fd_rdir = NULL;
 3539                         vnode_put(v_dir);
 3540                 } else {
 3541                         newfdp->fd_rdir = NULL;
 3542                 }
 3543         }
 3544         /* Coming from a chroot environment and unable to get a reference... */
 3545         if (newfdp->fd_rdir == NULL && fdp->fd_rdir) {
 3546                 /*
 3547                  * We couldn't get a new reference on
 3548                  * the chroot directory being
 3549                  * inherited... this is fatal, since
 3550                  * otherwise it would constitute an
 3551                  * escape from a chroot environment by
 3552                  * the new process.
 3553                  */
 3554                 if (newfdp->fd_cdir)
 3555                         vnode_rele(newfdp->fd_cdir);
 3556                 FREE_ZONE(newfdp, sizeof *newfdp, M_FILEDESC);
 3557                 return(NULL);
 3558         }
 3559         newfdp->fd_refcnt = 1;
 3560 
 3561         /*
 3562          * If the number of open files fits in the internal arrays
 3563          * of the open file structure, use them, otherwise allocate
 3564          * additional memory for the number of descriptors currently
 3565          * in use.
 3566          */
 3567         if (newfdp->fd_lastfile < NDFILE)
 3568                 i = NDFILE;
 3569         else {
 3570                 /*
 3571                  * Compute the smallest multiple of NDEXTENT needed
 3572                  * for the file descriptors currently in use,
 3573                  * allowing the table to shrink.
 3574                  */
 3575                 i = newfdp->fd_nfiles;
 3576                 while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2)
 3577                         i /= 2;
 3578         }
 3579         proc_fdunlock(p);
 3580 
 3581         MALLOC_ZONE(newfdp->fd_ofiles, struct fileproc **,
 3582                                 i * OFILESIZE, M_OFILETABL, M_WAITOK);
 3583         if (newfdp->fd_ofiles == NULL) {
 3584                 if (newfdp->fd_cdir)
 3585                         vnode_rele(newfdp->fd_cdir);
 3586                 if (newfdp->fd_rdir)
 3587                         vnode_rele(newfdp->fd_rdir);
 3588 
 3589                 FREE_ZONE(newfdp, sizeof(*newfdp), M_FILEDESC);
 3590                 return(NULL);
 3591         }
 3592         (void) memset(newfdp->fd_ofiles, 0, i * OFILESIZE);
 3593         proc_fdlock(p);
 3594 
 3595         newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
 3596         newfdp->fd_nfiles = i;
 3597 
 3598         if (fdp->fd_nfiles > 0) {
 3599                 struct fileproc **fpp;
 3600                 char *flags;
 3601 
 3602                 (void) memcpy(newfdp->fd_ofiles, fdp->fd_ofiles,
 3603                                         (newfdp->fd_lastfile + 1) * sizeof(*fdp->fd_ofiles));
 3604                 (void) memcpy(newfdp->fd_ofileflags, fdp->fd_ofileflags,
 3605                                         (newfdp->fd_lastfile + 1) * sizeof(*fdp->fd_ofileflags));
 3606 
 3607                 /*
 3608                  * kq descriptors cannot be copied.
 3609                  */
 3610                 if (newfdp->fd_knlistsize != -1) {
 3611                         fpp = &newfdp->fd_ofiles[newfdp->fd_lastfile];
 3612                         for (i = newfdp->fd_lastfile; i >= 0; i--, fpp--) {
 3613                                 if (*fpp != NULL && (*fpp)->f_type == DTYPE_KQUEUE) {
 3614                                         *fpp = NULL;
 3615                                         if (i < newfdp->fd_freefile)
 3616                                                 newfdp->fd_freefile = i;
 3617                                 }
 3618                                 if (*fpp == NULL && i == newfdp->fd_lastfile && i > 0)
 3619                                         newfdp->fd_lastfile--;
 3620                         }
 3621                         newfdp->fd_knlist = NULL;
 3622                         newfdp->fd_knlistsize = -1;
 3623                         newfdp->fd_knhash = NULL;
 3624                         newfdp->fd_knhashmask = 0;
 3625                 }
 3626                 fpp = newfdp->fd_ofiles;
 3627                 flags = newfdp->fd_ofileflags;
 3628 
 3629                 for (i = newfdp->fd_lastfile + 1; --i >= 0; fpp++, flags++)
 3630                         if ((ofp = *fpp) != NULL && !(*flags & UF_RESERVED)) {
 3631                                 MALLOC_ZONE(fp, struct fileproc *, sizeof(struct fileproc), M_FILEPROC, M_WAITOK);
 3632                                 if (fp == NULL) {
 3633                                         /*
 3634                                          * XXX no room to copy, unable to
 3635                                          * XXX safely unwind state at present
 3636                                          */
 3637                                         *fpp = NULL;
 3638                                 } else {
 3639                                         bzero(fp, sizeof(struct fileproc));
 3640                                         fp->f_flags = ofp->f_flags;
 3641                                         //fp->f_iocount = ofp->f_iocount;
 3642                                         fp->f_iocount = 0;
 3643                                         fp->f_fglob = ofp->f_fglob;
 3644                                         (void)fg_ref(fp);
 3645                                         *fpp = fp;
 3646                                 }
 3647                         } else {
 3648                                 if (i < newfdp->fd_freefile)
 3649                                         newfdp->fd_freefile = i;
 3650                                 *fpp = NULL;
 3651                                 *flags = 0;
 3652                         }
 3653         }
 3654 
 3655         proc_fdunlock(p);
 3656         return (newfdp);
 3657 }
 3658 
 3659 
 3660 /*
 3661  * fdfree
 3662  *
 3663  * Description: Release a filedesc (per process open file table) structure;
 3664  *              this is done on process exit(), or from forkproc_free() if
 3665  *              the fork fails for some reason subsequent to a successful
 3666  *              call to fdcopy()
 3667  *
 3668  * Parameters:  p                               Pointer to process going away
 3669  *
 3670  * Returns:     void
 3671  *
 3672  * Locks:       This function internally takes and drops proc_fdlock()
 3673  */
 3674 void
 3675 fdfree(proc_t p)
 3676 {
 3677         struct filedesc *fdp;
 3678         struct fileproc *fp;
 3679         int i;
 3680 
 3681         proc_fdlock(p);
 3682 
 3683         /* Certain daemons might not have file descriptors */
 3684         fdp = p->p_fd;
 3685 
 3686         if ((fdp == NULL) || (--fdp->fd_refcnt > 0)) {
 3687                 proc_fdunlock(p);
 3688                 return;
 3689         }
 3690         if (fdp->fd_refcnt == 0xffff)
 3691                 panic("fdfree: bad fd_refcnt");
 3692 
 3693         /* Last reference: the structure can't change out from under us */
 3694 
 3695         if (fdp->fd_nfiles > 0 && fdp->fd_ofiles) {
 3696                 for (i = fdp->fd_lastfile; i >= 0; i--) {
 3697                         if ((fp = fdp->fd_ofiles[i]) != NULL) {
 3698                           
 3699                           if (fdp->fd_ofileflags[i] & UF_RESERVED)
 3700                                 panic("fdfree: found fp with UF_RESERVED\n");
 3701 
 3702                                 /* closef drops the iocount ... */
 3703                                 if ((fp->f_flags & FP_INCHRREAD) != 0) 
 3704                                         fp->f_iocount++;
 3705                                 procfdtbl_reservefd(p, i);
 3706 
 3707                                 if (i < fdp->fd_knlistsize)
 3708                                         knote_fdclose(p, i);
 3709                                 if (fp->f_flags & FP_WAITEVENT) 
 3710                                         (void)waitevent_close(p, fp);
 3711                                 (void) closef_locked(fp, fp->f_fglob, p);
 3712                                 FREE_ZONE(fp, sizeof(*fp), M_FILEPROC);
 3713                         }
 3714                 }
 3715                 FREE_ZONE(fdp->fd_ofiles, fdp->fd_nfiles * OFILESIZE, M_OFILETABL);
 3716                 fdp->fd_ofiles = NULL;
 3717                 fdp->fd_nfiles = 0;
 3718         }        
 3719 
 3720         proc_fdunlock(p);
 3721         
 3722         if (fdp->fd_cdir)
 3723                 vnode_rele(fdp->fd_cdir);
 3724         if (fdp->fd_rdir)
 3725                 vnode_rele(fdp->fd_rdir);
 3726 
 3727         proc_fdlock_spin(p);
 3728         p->p_fd = NULL;
 3729         proc_fdunlock(p);
 3730 
 3731         if (fdp->fd_knlist)
 3732                 FREE(fdp->fd_knlist, M_KQUEUE);
 3733         if (fdp->fd_knhash)
 3734                 FREE(fdp->fd_knhash, M_KQUEUE);
 3735 
 3736         FREE_ZONE(fdp, sizeof(*fdp), M_FILEDESC);
 3737 }
 3738 
 3739 
 3740 /*
 3741  * closef_finish
 3742  *
 3743  * Description: Called on last open instance for a fileglob for a file being
 3744  *              closed.
 3745  *
 3746  * Parameters:  fp                      Pointer to fileproc for fd
 3747  *              fg                      Pointer to fileglob for fd
 3748  *              p                       Pointer to proc structure
 3749  *
 3750  * Returns:     0                       Success
 3751  *      <fo_close>:???                  Anything returnable by a per-fileops
 3752  *                                      close function
 3753  *
 3754  * Note:        fp can only be non-NULL if p is also non-NULL.  If p is NULL,
 3755  *              then fg must eith be locked (FHASLOCK) or must not have a
 3756  *              type of DTYPE_VNODE.
 3757  *
 3758  *              On return, the fg is freed.
 3759  *
 3760  *              This function may block draining output to a character
 3761  *              device on last close of that device.
 3762  */
 3763 static int
 3764 closef_finish(struct fileproc *fp, struct fileglob *fg, proc_t p, vfs_context_t ctx)
 3765 {
 3766         int error;
 3767 
 3768 
 3769         /* fg_ops completed initialization? */
 3770         if (fg->fg_ops)
 3771                 error = fo_close(fg, ctx);
 3772         else
 3773                 error = 0;
 3774 
 3775         /* if fp is non-NULL, drain it out */
 3776         if (((fp != (struct fileproc *)0) && ((fp->f_flags & FP_INCHRREAD) != 0))) {
 3777                 proc_fdlock_spin(p);
 3778                 if ( ((fp->f_flags & FP_INCHRREAD) != 0) ) {
 3779                         fileproc_drain(p, fp);
 3780                 }
 3781                 proc_fdunlock(p);
 3782         }
 3783         fg_free(fg);
 3784 
 3785         return (error);
 3786 }
 3787 
 3788 /*
 3789  * closef_locked
 3790  *
 3791  * Description: Internal form of closef; called with proc_fdlock held
 3792  *
 3793  * Parameters:  fp                      Pointer to fileproc for fd
 3794  *              fg                      Pointer to fileglob for fd
 3795  *              p                       Pointer to proc structure
 3796  *
 3797  * Returns:     0                       Success
 3798  *      closef_finish:???               Anything returnable by a per-fileops
 3799  *                                      close function
 3800  *
 3801  * Note:        Decrements reference count on file structure; if this was the
 3802  *              last reference, then closef_finish() is called
 3803  *
 3804  *              p and fp are allowed to  be NULL when closing a file that was
 3805  *              being passed in a message (but only if we are called when this
 3806  *              is NOT the last reference).
 3807  */
 3808 int
 3809 closef_locked(struct fileproc *fp, struct fileglob *fg, proc_t p)
 3810 {
 3811         struct vnode *vp;
 3812         struct flock lf;
 3813         struct vfs_context context;
 3814         int error;
 3815 
 3816         if (fg == NULL) {
 3817                 return (0);
 3818         }
 3819 
 3820         /* Set up context with cred stashed in fg */
 3821         if (p == current_proc())
 3822                 context.vc_thread = current_thread();
 3823         else
 3824                 context.vc_thread = NULL;
 3825         context.vc_ucred = fg->fg_cred;
 3826 
 3827         /*
 3828          * POSIX record locking dictates that any close releases ALL
 3829          * locks owned by this process.  This is handled by setting
 3830          * a flag in the unlock to free ONLY locks obeying POSIX
 3831          * semantics, and not to free BSD-style file locks.
 3832          * If the descriptor was in a message, POSIX-style locks
 3833          * aren't passed with the descriptor.
 3834          */
 3835         if (p && (p->p_ladvflag & P_LADVLOCK) && fg->fg_type == DTYPE_VNODE) {
 3836                 proc_fdunlock(p);
 3837 
 3838                 lf.l_whence = SEEK_SET;
 3839                 lf.l_start = 0;
 3840                 lf.l_len = 0;
 3841                 lf.l_type = F_UNLCK;
 3842                 vp = (struct vnode *)fg->fg_data;
 3843 
 3844                 if ( (error = vnode_getwithref(vp)) == 0 ) {
 3845                         (void) VNOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX, &context);
 3846                         (void)vnode_put(vp);
 3847                 }
 3848                 proc_fdlock(p);
 3849         }
 3850         lck_mtx_lock_spin(&fg->fg_lock);
 3851         fg->fg_count--;
 3852 
 3853         if (fg->fg_count > 0) {
 3854                 lck_mtx_unlock(&fg->fg_lock);
 3855                 return (0);
 3856         }
 3857 #if DIAGNOSTIC
 3858         if (fg->fg_count != 0)
 3859                 panic("fg %p: being freed with bad fg_count (%d)", fg, fg->fg_count);
 3860 #endif
 3861 
 3862         if (fp && (fp->f_flags & FP_WRITTEN))
 3863                 fg->fg_flag |= FWASWRITTEN;
 3864 
 3865         fg->fg_lflags |= FG_TERM;
 3866         lck_mtx_unlock(&fg->fg_lock);
 3867 
 3868         proc_fdunlock(p);
 3869         error = closef_finish(fp, fg, p, &context);
 3870         proc_fdlock(p);
 3871 
 3872         return(error);
 3873 }
 3874 
 3875 
 3876 /* sleep address to permit wakeup of select by fileproc_drain() */
 3877 extern int selwait;
 3878 
 3879 
 3880 /*
 3881  * fileproc_drain
 3882  *
 3883  * Description: Drain out pending I/O operations
 3884  *
 3885  * Parameters:  p                               Process closing this file
 3886  *              fp                              fileproc struct for the open
 3887  *                                              instance on the file
 3888  *
 3889  * Returns:     void
 3890  *
 3891  * Locks:       Assumes the caller holds the proc_fdlock
 3892  *
 3893  * Notes:       For character devices, this occurs on the last close of the
 3894  *              device; for all other file descriptos, this occurs on each
 3895  *              close to prevent fd's from being closed out from under
 3896  *              operations currently in progress and blocked
 3897  *
 3898  * See Also:    file_vnode(), file_socket(), file_drop(), and the cautions
 3899  *              regarding their use and interaction with this function.
 3900  */
 3901 void
 3902 fileproc_drain(proc_t p, struct fileproc * fp)
 3903 {
 3904         struct vfs_context context;
 3905 
 3906         context.vc_thread = proc_thread(p);     /* XXX */
 3907         context.vc_ucred = fp->f_fglob->fg_cred;
 3908 
 3909         fp->f_iocount-- ; /* (the one the close holds) */
 3910 
 3911         while (fp->f_iocount) {
 3912 
 3913                 lck_mtx_convert_spin(&p->p_fdmlock);
 3914 
 3915                 if (((fp->f_flags & FP_INSELECT)== FP_INSELECT)) {
 3916                         wait_queue_wakeup_all((wait_queue_t)fp->f_waddr, &selwait, THREAD_INTERRUPTED);
 3917                 } else  {
 3918                         if (fp->f_fglob->fg_ops->fo_drain) {
 3919                                 (*fp->f_fglob->fg_ops->fo_drain)(fp, &context);
 3920                         }
 3921                 }
 3922                 p->p_fpdrainwait = 1;
 3923 
 3924                 msleep(&p->p_fpdrainwait, &p->p_fdmlock, PRIBIO, "fpdrain", NULL);
 3925 
 3926         }
 3927 }
 3928 
 3929 
 3930 /*
 3931  * fp_free
 3932  *
 3933  * Description: Release the fd and free the fileproc associated with the fd
 3934  *              in the per process open file table of the specified process;
 3935  *              these values must correspond.
 3936  *
 3937  * Parameters:  p                               Process containing fd
 3938  *              fd                              fd to be released
 3939  *              fp                              fileproc to be freed
 3940  *
 3941  * Returns:     0                               Success
 3942  *
 3943  * Notes:       XXX function should be void - no one interprets the returns
 3944  *              XXX code
 3945  */
 3946 int
 3947 fp_free(proc_t p, int fd, struct fileproc * fp)
 3948 {
 3949         proc_fdlock_spin(p);
 3950         fdrelse(p, fd);
 3951         proc_fdunlock(p);
 3952 
 3953         fg_free(fp->f_fglob);
 3954         FREE_ZONE(fp, sizeof(*fp), M_FILEPROC);
 3955         return(0);
 3956 }
 3957 
 3958 
 3959 /*
 3960  * flock
 3961  *
 3962  * Description: Apply an advisory lock on a file descriptor.
 3963  *
 3964  * Parameters:  p                               Process making request
 3965  *              uap->fd                         fd on which the lock is to be
 3966  *                                              attempted
 3967  *              uap->how                        (Un)Lock bits, including type
 3968  *              retval                          Pointer to the call return area
 3969  *              
 3970  * Returns:     0                               Success
 3971  *      fp_getfvp:EBADF                         Bad file descriptor
 3972  *      fp_getfvp:ENOTSUP                       fd does not refer to a vnode
 3973  *      vnode_getwithref:???
 3974  *      VNOP_ADVLOCK:???
 3975  *
 3976  * Implicit returns:
 3977  *              *retval (modified)              Size of dtable
 3978  *
 3979  * Notes:       Just attempt to get a record lock of the requested type on
 3980  *              the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
 3981  */
 3982 int
 3983 flock(proc_t p, struct flock_args *uap, __unused register_t *retval)
 3984 {
 3985         int fd = uap->fd;
 3986         int how = uap->how;
 3987         struct fileproc *fp;
 3988         struct vnode *vp;
 3989         struct flock lf;
 3990         vfs_context_t ctx = vfs_context_current();
 3991         int error=0;
 3992 
 3993         AUDIT_ARG(fd, uap->fd);
 3994         if ( (error = fp_getfvp(p, fd, &fp, &vp)) ) {
 3995                 return(error);
 3996         }
 3997         if ( (error = vnode_getwithref(vp)) ) {
 3998                 goto out1;
 3999         }
 4000         AUDIT_ARG(vnpath, vp, ARG_VNODE1);
 4001 
 4002         lf.l_whence = SEEK_SET;
 4003         lf.l_start = 0;
 4004         lf.l_len = 0;
 4005         if (how & LOCK_UN) {
 4006                 lf.l_type = F_UNLCK;
 4007                 fp->f_flag &= ~FHASLOCK;
 4008                 error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_UNLCK, &lf, F_FLOCK, ctx);
 4009                 goto out;
 4010         }
 4011         if (how & LOCK_EX)
 4012                 lf.l_type = F_WRLCK;
 4013         else if (how & LOCK_SH)
 4014                 lf.l_type = F_RDLCK;
 4015         else {
 4016                 error = EBADF;
 4017                 goto out;
 4018         }
 4019 #if CONFIG_MACF
 4020         error = mac_file_check_lock(proc_ucred(p), fp->f_fglob, F_SETLK, &lf);
 4021         if (error)
 4022                 goto out;
 4023 #endif
 4024         fp->f_flag |= FHASLOCK;
 4025         if (how & LOCK_NB) {
 4026                 error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, F_FLOCK, ctx);
 4027                 goto out;       
 4028         }
 4029         error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, F_FLOCK|F_WAIT, ctx);
 4030 out:
 4031         (void)vnode_put(vp);
 4032 out1:
 4033         fp_drop(p, fd, fp, 0);
 4034         return(error);
 4035 
 4036 }
 4037 
 4038 /*
 4039  * dupfdopen
 4040  *
 4041  * Description: Duplicate the specified descriptor to a free descriptor;
 4042  *              this is the second half of fdopen(), above.
 4043  *
 4044  * Parameters:  fdp                             filedesc pointer to fill in
 4045  *              indx                            fd to dup to
 4046  *              dfd                             fd to dup from
 4047  *              mode                            mode to set on new fd
 4048  *              error                           command code
 4049  *
 4050  * Returns:     0                               Success
 4051  *              EBADF                           Source fd is bad
 4052  *              EACCES                          Requested mode not allowed
 4053  *              !0                              'error', if not ENODEV or
 4054  *                                              ENXIO
 4055  *
 4056  * Notes:       XXX This is not thread safe; see fdopen() above
 4057  */
 4058 int
 4059 dupfdopen(struct filedesc *fdp, int indx, int dfd, int mode, int error)
 4060 {
 4061         struct fileproc *wfp;
 4062         struct fileproc *fp;
 4063 #if CONFIG_MACF
 4064         int myerror;
 4065 #endif
 4066         proc_t p = current_proc();
 4067 
 4068         /*
 4069          * If the to-be-dup'd fd number is greater than the allowed number
 4070          * of file descriptors, or the fd to be dup'd has already been
 4071          * closed, reject.  Note, check for new == old is necessary as
 4072          * falloc could allocate an already closed to-be-dup'd descriptor
 4073          * as the new descriptor.
 4074          */
 4075         proc_fdlock(p);
 4076 
 4077         fp = fdp->fd_ofiles[indx];
 4078         if (dfd < 0 || dfd >= fdp->fd_nfiles ||
 4079                         (wfp = fdp->fd_ofiles[dfd]) == NULL || wfp == fp ||
 4080                         (fdp->fd_ofileflags[dfd] & UF_RESERVED)) {
 4081 
 4082                 proc_fdunlock(p);
 4083                 return (EBADF);
 4084         }
 4085 #if CONFIG_MACF
 4086         myerror = mac_file_check_dup(proc_ucred(p), wfp->f_fglob, dfd);
 4087         if (myerror) {
 4088                 proc_fdunlock(p);
 4089                 return (myerror);
 4090         }
 4091 #endif
 4092         /*
 4093          * There are two cases of interest here.
 4094          *
 4095          * For ENODEV simply dup (dfd) to file descriptor
 4096          * (indx) and return.
 4097          *
 4098          * For ENXIO steal away the file structure from (dfd) and
 4099          * store it in (indx).  (dfd) is effectively closed by
 4100          * this operation.
 4101          *
 4102          * Any other error code is just returned.
 4103          */
 4104         switch (error) {
 4105         case ENODEV:
 4106                 /*
 4107                  * Check that the mode the file is being opened for is a
 4108                  * subset of the mode of the existing descriptor.
 4109                  */
 4110                 if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) {
 4111                         proc_fdunlock(p);
 4112                         return (EACCES);
 4113                 }
 4114                 if (indx > fdp->fd_lastfile)
 4115                         fdp->fd_lastfile = indx;
 4116                 (void)fg_ref(wfp);
 4117 
 4118                 if (fp->f_fglob)
 4119                         fg_free(fp->f_fglob);
 4120                 fp->f_fglob = wfp->f_fglob;
 4121 
 4122                 fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
 4123 
 4124                 proc_fdunlock(p);
 4125                 return (0);
 4126 
 4127         default:
 4128                 proc_fdunlock(p);
 4129                 return (error);
 4130         }
 4131         /* NOTREACHED */
 4132 }
 4133 
 4134 
 4135 /*
 4136  * fg_ref
 4137  *
 4138  * Description: Add a reference to a fileglob by fileproc
 4139  *
 4140  * Parameters:  fp                              fileproc containing fileglob
 4141  *                                              pointer
 4142  *
 4143  * Returns:     void
 4144  *
 4145  * Notes:       XXX Should use OSAddAtomic?
 4146  */
 4147 void
 4148 fg_ref(struct fileproc * fp)
 4149 {
 4150         struct fileglob *fg;
 4151 
 4152         fg = fp->f_fglob;
 4153 
 4154         lck_mtx_lock_spin(&fg->fg_lock);
 4155 
 4156 #if DIAGNOSTIC
 4157         if ((fp->f_flags & ~((unsigned int)FP_VALID_FLAGS)) != 0)
 4158                 panic("fg_ref: invalid bits on fp%x\n", (unsigned int)fp);
 4159 
 4160         if (fg->fg_count == 0)
 4161                 panic("fg_ref: adding fgcount to zeroed fg :fp %x, fg%x\n ", (unsigned int)fp, (unsigned int)fg);
 4162 #endif
 4163         fg->fg_count++;
 4164         lck_mtx_unlock(&fg->fg_lock);
 4165 }
 4166 
 4167 
 4168 /*
 4169  * fg_drop
 4170  *
 4171  * Description: Remove a reference to a fileglob by fileproc
 4172  *
 4173  * Parameters:  fp                              fileproc containing fileglob
 4174  *                                              pointer
 4175  *
 4176  * Returns:     void
 4177  *
 4178  * Notes:       XXX Should use OSAddAtomic?
 4179  */
 4180 void
 4181 fg_drop(struct fileproc * fp)
 4182 {
 4183         struct fileglob *fg;
 4184 
 4185         fg = fp->f_fglob;
 4186         lck_mtx_lock_spin(&fg->fg_lock);
 4187         fg->fg_count--;
 4188         lck_mtx_unlock(&fg->fg_lock);
 4189 }
 4190 
 4191 
 4192 /*
 4193  * fg_insertuipc
 4194  *
 4195  * Description: Insert fileglob onto message queue
 4196  *
 4197  * Parameters:  fg                              Fileglob pointer to insert
 4198  *
 4199  * Returns:     void
 4200  *
 4201  * Locks:       Takes and drops fg_lock, potentially many times
 4202  */
 4203 void
 4204 fg_insertuipc(struct fileglob * fg)
 4205 {
 4206         int insertque = 0;
 4207 
 4208         lck_mtx_lock_spin(&fg->fg_lock);
 4209 
 4210         while (fg->fg_lflags & FG_RMMSGQ) {
 4211                 lck_mtx_convert_spin(&fg->fg_lock);
 4212 
 4213                 fg->fg_lflags |= FG_WRMMSGQ;
 4214                 msleep(&fg->fg_lflags, &fg->fg_lock, 0, "fg_insertuipc", NULL);
 4215         }
 4216 
 4217         fg->fg_count++;
 4218         fg->fg_msgcount++;
 4219         if (fg->fg_msgcount == 1) {
 4220                 fg->fg_lflags |= FG_INSMSGQ;
 4221                 insertque=1;
 4222         }
 4223         lck_mtx_unlock(&fg->fg_lock);
 4224 
 4225         if (insertque) {
 4226                 lck_mtx_lock_spin(uipc_lock);
 4227                 unp_gc_wait();
 4228                 LIST_INSERT_HEAD(&fmsghead, fg, f_msglist);
 4229                 lck_mtx_unlock(uipc_lock);
 4230                 lck_mtx_lock(&fg->fg_lock);
 4231                 fg->fg_lflags &= ~FG_INSMSGQ;
 4232                 if (fg->fg_lflags & FG_WINSMSGQ) {
 4233                         fg->fg_lflags &= ~FG_WINSMSGQ;
 4234                         wakeup(&fg->fg_lflags);
 4235                 }
 4236                 lck_mtx_unlock(&fg->fg_lock);
 4237         }
 4238 
 4239 }
 4240 
 4241 
 4242 /*
 4243  * fg_removeuipc
 4244  *
 4245  * Description: Remove fileglob from message queue
 4246  *
 4247  * Parameters:  fg                              Fileglob pointer to remove
 4248  *
 4249  * Returns:     void
 4250  *
 4251  * Locks:       Takes and drops fg_lock, potentially many times
 4252  */
 4253 void
 4254 fg_removeuipc(struct fileglob * fg)
 4255 {
 4256         int removeque = 0;
 4257 
 4258         lck_mtx_lock_spin(&fg->fg_lock);
 4259         while (fg->fg_lflags & FG_INSMSGQ) {
 4260                 lck_mtx_convert_spin(&fg->fg_lock);
 4261 
 4262                 fg->fg_lflags |= FG_WINSMSGQ;
 4263                 msleep(&fg->fg_lflags, &fg->fg_lock, 0, "fg_removeuipc", NULL);
 4264         }
 4265         fg->fg_msgcount--;
 4266         if (fg->fg_msgcount == 0) {
 4267                 fg->fg_lflags |= FG_RMMSGQ;
 4268                 removeque=1;
 4269         }
 4270         lck_mtx_unlock(&fg->fg_lock);
 4271 
 4272         if (removeque) {
 4273                 lck_mtx_lock_spin(uipc_lock);
 4274                 unp_gc_wait();
 4275                 LIST_REMOVE(fg, f_msglist);
 4276                 lck_mtx_unlock(uipc_lock);
 4277                 lck_mtx_lock(&fg->fg_lock);
 4278                 fg->fg_lflags &= ~FG_RMMSGQ;
 4279                 if (fg->fg_lflags & FG_WRMMSGQ) {
 4280                         fg->fg_lflags &= ~FG_WRMMSGQ;
 4281                         wakeup(&fg->fg_lflags);
 4282                 }
 4283                 lck_mtx_unlock(&fg->fg_lock);
 4284         }
 4285 }
 4286 
 4287 
 4288 /*
 4289  * fo_read
 4290  *
 4291  * Description: Generic fileops read indirected through the fileops pointer
 4292  *              in the fileproc structure
 4293  *
 4294  * Parameters:  fp                              fileproc structure pointer
 4295  *              uio                             user I/O structure pointer
 4296  *              flags                           FOF_ flags
 4297  *              ctx                             VFS context for operation
 4298  *
 4299  * Returns:     0                               Success
 4300  *              !0                              Errno from read
 4301  */
 4302 int
 4303 fo_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
 4304 {
 4305         return ((*fp->f_ops->fo_read)(fp, uio, flags, ctx));
 4306 }
 4307 
 4308 
 4309 /*
 4310  * fo_write
 4311  *
 4312  * Description: Generic fileops write indirected through the fileops pointer
 4313  *              in the fileproc structure
 4314  *
 4315  * Parameters:  fp                              fileproc structure pointer
 4316  *              uio                             user I/O structure pointer
 4317  *              flags                           FOF_ flags
 4318  *              ctx                             VFS context for operation
 4319  *
 4320  * Returns:     0                               Success
 4321  *              !0                              Errno from write
 4322  */
 4323 int
 4324 fo_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
 4325 {
 4326         return((*fp->f_ops->fo_write)(fp, uio, flags, ctx));
 4327 }
 4328 
 4329 
 4330 /*
 4331  * fo_ioctl
 4332  *
 4333  * Description: Generic fileops ioctl indirected through the fileops pointer
 4334  *              in the fileproc structure
 4335  *
 4336  * Parameters:  fp                              fileproc structure pointer
 4337  *              com                             ioctl command
 4338  *              data                            pointer to internalized copy
 4339  *                                              of user space ioctl command
 4340  *                                              parameter data in kernel space
 4341  *              ctx                             VFS context for operation
 4342  *
 4343  * Returns:     0                               Success
 4344  *              !0                              Errno from ioctl
 4345  *
 4346  * Locks:       The caller is assumed to have held the proc_fdlock; this
 4347  *              function releases and reacquires this lock.  If the caller
 4348  *              accesses data protected by this lock prior to calling this
 4349  *              function, it will need to revalidate/reacquire any cached
 4350  *              protected data obtained prior to the call.
 4351  */
 4352 int 
 4353 fo_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
 4354 {
 4355         int error;
 4356 
 4357         proc_fdunlock(vfs_context_proc(ctx));
 4358         error = (*fp->f_ops->fo_ioctl)(fp, com, data, ctx);
 4359         proc_fdlock(vfs_context_proc(ctx));
 4360         return(error);
 4361 }       
 4362 
 4363 
 4364 /*
 4365  * fo_select
 4366  *
 4367  * Description: Generic fileops select indirected through the fileops pointer
 4368  *              in the fileproc structure
 4369  *
 4370  * Parameters:  fp                              fileproc structure pointer
 4371  *              which                           select which
 4372  *              wql                             pointer to wait queue list
 4373  *              ctx                             VFS context for operation
 4374  *
 4375  * Returns:     0                               Success
 4376  *              !0                              Errno from select
 4377  */
 4378 int
 4379 fo_select(struct fileproc *fp, int which, void *wql, vfs_context_t ctx)
 4380 {       
 4381         return((*fp->f_ops->fo_select)(fp, which, wql, ctx));
 4382 }
 4383 
 4384 
 4385 /*
 4386  * fo_close
 4387  *
 4388  * Description: Generic fileops close indirected through the fileops pointer
 4389  *              in the fileproc structure
 4390  *
 4391  * Parameters:  fp                              fileproc structure pointer for
 4392  *                                              file to close
 4393  *              ctx                             VFS context for operation
 4394  *
 4395  * Returns:     0                               Success
 4396  *              !0                              Errno from close
 4397  */
 4398 int
 4399 fo_close(struct fileglob *fg, vfs_context_t ctx)
 4400 {       
 4401         return((*fg->fg_ops->fo_close)(fg, ctx));
 4402 }
 4403 
 4404 
 4405 /*
 4406  * fo_kqfilter
 4407  *
 4408  * Description: Generic fileops kqueue filter indirected through the fileops
 4409  *              pointer in the fileproc structure
 4410  *
 4411  * Parameters:  fp                              fileproc structure pointer
 4412  *              kn                              pointer to knote to filter on
 4413  *              ctx                             VFS context for operation
 4414  *
 4415  * Returns:     0                               Success
 4416  *              !0                              Errno from kqueue filter
 4417  */
 4418 int
 4419 fo_kqfilter(struct fileproc *fp, struct knote *kn, vfs_context_t ctx)
 4420 {
 4421         return ((*fp->f_ops->fo_kqfilter)(fp, kn, ctx));
 4422 }

Cache object: 790cf39e968504fd18c0033038947018


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.