LCOV - code coverage report
Current view: top level - kern - kern_descrip.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 713 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 37 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: kern_descrip.c,v 1.182 2018/08/24 12:45:27 visa Exp $ */
       2             : /*      $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $       */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1982, 1986, 1989, 1991, 1993
       6             :  *      The Regents of the University of California.  All rights reserved.
       7             :  * (c) UNIX System Laboratories, Inc.
       8             :  * All or some portions of this file are derived from material licensed
       9             :  * to the University of California by American Telephone and Telegraph
      10             :  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      11             :  * the permission of UNIX System Laboratories, Inc.
      12             :  *
      13             :  * Redistribution and use in source and binary forms, with or without
      14             :  * modification, are permitted provided that the following conditions
      15             :  * are met:
      16             :  * 1. Redistributions of source code must retain the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer.
      18             :  * 2. Redistributions in binary form must reproduce the above copyright
      19             :  *    notice, this list of conditions and the following disclaimer in the
      20             :  *    documentation and/or other materials provided with the distribution.
      21             :  * 3. Neither the name of the University nor the names of its contributors
      22             :  *    may be used to endorse or promote products derived from this software
      23             :  *    without specific prior written permission.
      24             :  *
      25             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      26             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      27             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      28             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      29             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      30             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      31             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      32             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      33             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      34             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      35             :  * SUCH DAMAGE.
      36             :  *
      37             :  *      @(#)kern_descrip.c      8.6 (Berkeley) 4/19/94
      38             :  */
      39             : 
      40             : #include <sys/param.h>
      41             : #include <sys/systm.h>
      42             : #include <sys/filedesc.h>
      43             : #include <sys/kernel.h>
      44             : #include <sys/vnode.h>
      45             : #include <sys/proc.h>
      46             : #include <sys/file.h>
      47             : #include <sys/socket.h>
      48             : #include <sys/socketvar.h>
      49             : #include <sys/stat.h>
      50             : #include <sys/ioctl.h>
      51             : #include <sys/fcntl.h>
      52             : #include <sys/lock.h>
      53             : #include <sys/malloc.h>
      54             : #include <sys/syslog.h>
      55             : #include <sys/ucred.h>
      56             : #include <sys/unistd.h>
      57             : #include <sys/resourcevar.h>
      58             : #include <sys/mount.h>
      59             : #include <sys/syscallargs.h>
      60             : #include <sys/event.h>
      61             : #include <sys/pool.h>
      62             : #include <sys/ktrace.h>
      63             : #include <sys/pledge.h>
      64             : 
      65             : #include <sys/pipe.h>
      66             : 
      67             : /*
      68             :  * Descriptor management.
      69             :  *
      70             :  * We need to block interrupts as long as `fhdlk' is being taken
      71             :  * with and without the KERNEL_LOCK().
      72             :  */
      73             : struct mutex fhdlk = MUTEX_INITIALIZER(IPL_MPFLOOR);
      74             : struct filelist filehead;       /* head of list of open files */
      75             : int numfiles;                   /* actual number of open files */
      76             : 
      77             : static __inline void fd_used(struct filedesc *, int);
      78             : static __inline void fd_unused(struct filedesc *, int);
      79             : static __inline int find_next_zero(u_int *, int, u_int);
      80             : static __inline int fd_inuse(struct filedesc *, int);
      81             : int finishdup(struct proc *, struct file *, int, int, register_t *, int);
      82             : int find_last_set(struct filedesc *, int);
      83             : int dodup3(struct proc *, int, int, int, register_t *);
      84             : 
      85             : struct pool file_pool;
      86             : struct pool fdesc_pool;
      87             : 
      88             : void
      89           0 : filedesc_init(void)
      90             : {
      91           0 :         pool_init(&file_pool, sizeof(struct file), 0, IPL_MPFLOOR,
      92             :             PR_WAITOK, "filepl", NULL);
      93           0 :         pool_init(&fdesc_pool, sizeof(struct filedesc0), 0, IPL_NONE,
      94             :             PR_WAITOK, "fdescpl", NULL);
      95           0 :         LIST_INIT(&filehead);
      96           0 : }
      97             : 
      98             : static __inline int
      99           0 : find_next_zero (u_int *bitmap, int want, u_int bits)
     100             : {
     101             :         int i, off, maxoff;
     102             :         u_int sub;
     103             : 
     104           0 :         if (want > bits)
     105           0 :                 return -1;
     106             : 
     107           0 :         off = want >> NDENTRYSHIFT;
     108           0 :         i = want & NDENTRYMASK;
     109           0 :         if (i) {
     110           0 :                 sub = bitmap[off] | ((u_int)~0 >> (NDENTRIES - i));
     111           0 :                 if (sub != ~0)
     112             :                         goto found;
     113           0 :                 off++;
     114           0 :         }
     115             : 
     116           0 :         maxoff = NDLOSLOTS(bits);
     117           0 :         while (off < maxoff) {
     118           0 :                 if ((sub = bitmap[off]) != ~0)
     119             :                         goto found;
     120           0 :                 off++;
     121             :         }
     122             : 
     123           0 :         return -1;
     124             : 
     125             :  found:
     126           0 :         return (off << NDENTRYSHIFT) + ffs(~sub) - 1;
     127           0 : }
     128             : 
     129             : int
     130           0 : find_last_set(struct filedesc *fd, int last)
     131             : {
     132             :         int off, i;
     133           0 :         u_int *bitmap = fd->fd_lomap;
     134             : 
     135           0 :         off = (last - 1) >> NDENTRYSHIFT;
     136             : 
     137           0 :         while (off >= 0 && !bitmap[off])
     138           0 :                 off--;
     139           0 :         if (off < 0)
     140           0 :                 return 0;
     141             : 
     142           0 :         i = ((off + 1) << NDENTRYSHIFT) - 1;
     143           0 :         if (i >= last)
     144           0 :                 i = last - 1;
     145             : 
     146           0 :         while (i > 0 && !fd_inuse(fd, i))
     147           0 :                 i--;
     148           0 :         return i;
     149           0 : }
     150             : 
     151             : static __inline int
     152           0 : fd_inuse(struct filedesc *fdp, int fd)
     153             : {
     154           0 :         u_int off = fd >> NDENTRYSHIFT;
     155             : 
     156           0 :         if (fdp->fd_lomap[off] & (1 << (fd & NDENTRYMASK)))
     157           0 :                 return 1;
     158             : 
     159           0 :         return 0;
     160           0 : }
     161             : 
     162             : static __inline void
     163           0 : fd_used(struct filedesc *fdp, int fd)
     164             : {
     165           0 :         u_int off = fd >> NDENTRYSHIFT;
     166             : 
     167           0 :         fdp->fd_lomap[off] |= 1 << (fd & NDENTRYMASK);
     168           0 :         if (fdp->fd_lomap[off] == ~0)
     169           0 :                 fdp->fd_himap[off >> NDENTRYSHIFT] |= 1 << (off & NDENTRYMASK);
     170             : 
     171           0 :         if (fd > fdp->fd_lastfile)
     172           0 :                 fdp->fd_lastfile = fd;
     173           0 :         fdp->fd_openfd++;
     174           0 : }
     175             : 
     176             : static __inline void
     177           0 : fd_unused(struct filedesc *fdp, int fd)
     178             : {
     179           0 :         u_int off = fd >> NDENTRYSHIFT;
     180             : 
     181           0 :         if (fd < fdp->fd_freefile)
     182           0 :                 fdp->fd_freefile = fd;
     183             : 
     184           0 :         if (fdp->fd_lomap[off] == ~0)
     185           0 :                 fdp->fd_himap[off >> NDENTRYSHIFT] &= ~(1 << (off & NDENTRYMASK));
     186           0 :         fdp->fd_lomap[off] &= ~(1 << (fd & NDENTRYMASK));
     187             : 
     188             : #ifdef DIAGNOSTIC
     189           0 :         if (fd > fdp->fd_lastfile)
     190           0 :                 panic("fd_unused: fd_lastfile inconsistent");
     191             : #endif
     192           0 :         if (fd == fdp->fd_lastfile)
     193           0 :                 fdp->fd_lastfile = find_last_set(fdp, fd);
     194           0 :         fdp->fd_openfd--;
     195           0 : }
     196             : 
     197             : struct file *
     198           0 : fd_iterfile(struct file *fp, struct proc *p)
     199             : {
     200             :         struct file *nfp;
     201             :         unsigned int count;
     202             : 
     203           0 :         mtx_enter(&fhdlk);
     204           0 :         if (fp == NULL)
     205           0 :                 nfp = LIST_FIRST(&filehead);
     206             :         else
     207           0 :                 nfp = LIST_NEXT(fp, f_list);
     208             : 
     209             :         /* don't refcount when f_count == 0 to avoid race in fdrop() */
     210           0 :         while (nfp != NULL) {
     211           0 :                 count = nfp->f_count;
     212           0 :                 if (count == 0) {
     213           0 :                         nfp = LIST_NEXT(nfp, f_list);
     214           0 :                         continue;
     215             :                 }
     216           0 :                 if (atomic_cas_uint(&nfp->f_count, count, count + 1) == count)
     217             :                         break;
     218             :         }
     219           0 :         mtx_leave(&fhdlk);
     220             : 
     221           0 :         if (fp != NULL)
     222           0 :                 FRELE(fp, p);
     223             : 
     224           0 :         return nfp;
     225             : }
     226             : 
     227             : struct file *
     228           0 : fd_getfile(struct filedesc *fdp, int fd)
     229             : {
     230             :         struct file *fp;
     231             : 
     232           0 :         vfs_stall_barrier();
     233             : 
     234           0 :         if ((u_int)fd >= fdp->fd_nfiles)
     235           0 :                 return (NULL);
     236             : 
     237           0 :         mtx_enter(&fdp->fd_fplock);
     238           0 :         fp = fdp->fd_ofiles[fd];
     239           0 :         if (fp != NULL)
     240           0 :                 atomic_inc_int(&fp->f_count);
     241           0 :         mtx_leave(&fdp->fd_fplock);
     242             : 
     243           0 :         return (fp);
     244           0 : }
     245             : 
     246             : struct file *
     247           0 : fd_getfile_mode(struct filedesc *fdp, int fd, int mode)
     248             : {
     249             :         struct file *fp;
     250             : 
     251           0 :         KASSERT(mode != 0);
     252             : 
     253           0 :         fp = fd_getfile(fdp, fd);
     254           0 :         if (fp == NULL)
     255           0 :                 return (NULL);
     256             : 
     257           0 :         if ((fp->f_flag & mode) == 0) {
     258           0 :                 FRELE(fp, curproc);
     259           0 :                 return (NULL);
     260             :         }
     261             : 
     262           0 :         return (fp);
     263           0 : }
     264             : 
     265             : /*
     266             :  * System calls on descriptors.
     267             :  */
     268             : 
     269             : /*
     270             :  * Duplicate a file descriptor.
     271             :  */
     272             : int
     273           0 : sys_dup(struct proc *p, void *v, register_t *retval)
     274             : {
     275             :         struct sys_dup_args /* {
     276             :                 syscallarg(int) fd;
     277           0 :         } */ *uap = v;
     278           0 :         struct filedesc *fdp = p->p_fd;
     279           0 :         int old = SCARG(uap, fd);
     280             :         struct file *fp;
     281           0 :         int new;
     282           0 :         int error;
     283             : 
     284             : restart:
     285           0 :         if ((fp = fd_getfile(fdp, old)) == NULL)
     286           0 :                 return (EBADF);
     287           0 :         fdplock(fdp);
     288           0 :         if ((error = fdalloc(p, 0, &new)) != 0) {
     289           0 :                 FRELE(fp, p);
     290           0 :                 if (error == ENOSPC) {
     291           0 :                         fdexpand(p);
     292           0 :                         fdpunlock(fdp);
     293           0 :                         goto restart;
     294             :                 }
     295             :                 goto out;
     296             :         }
     297             :         /* No need for FRELE(), finishdup() uses current ref. */
     298           0 :         error = finishdup(p, fp, old, new, retval, 0);
     299             : 
     300             : out:
     301           0 :         fdpunlock(fdp);
     302           0 :         return (error);
     303           0 : }
     304             : 
     305             : /*
     306             :  * Duplicate a file descriptor to a particular value.
     307             :  */
     308             : int
     309           0 : sys_dup2(struct proc *p, void *v, register_t *retval)
     310             : {
     311             :         struct sys_dup2_args /* {
     312             :                 syscallarg(int) from;
     313             :                 syscallarg(int) to;
     314           0 :         } */ *uap = v;
     315             : 
     316           0 :         return (dodup3(p, SCARG(uap, from), SCARG(uap, to), 0, retval));
     317             : }
     318             : 
     319             : int
     320           0 : sys_dup3(struct proc *p, void *v, register_t *retval)
     321             : {
     322             :         struct sys_dup3_args /* {
     323             :                 syscallarg(int) from;
     324             :                 syscallarg(int) to;
     325             :                 syscallarg(int) flags;
     326           0 :         } */ *uap = v;
     327             : 
     328           0 :         if (SCARG(uap, from) == SCARG(uap, to))
     329           0 :                 return (EINVAL);
     330           0 :         if (SCARG(uap, flags) & ~O_CLOEXEC)
     331           0 :                 return (EINVAL);
     332           0 :         return (dodup3(p, SCARG(uap, from), SCARG(uap, to),
     333             :             SCARG(uap, flags), retval));
     334           0 : }
     335             : 
     336             : int
     337           0 : dodup3(struct proc *p, int old, int new, int flags, register_t *retval)
     338             : {
     339           0 :         struct filedesc *fdp = p->p_fd;
     340             :         struct file *fp;
     341           0 :         int i, error;
     342             : 
     343             : restart:
     344           0 :         if ((fp = fd_getfile(fdp, old)) == NULL)
     345           0 :                 return (EBADF);
     346           0 :         if ((u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
     347           0 :             (u_int)new >= maxfiles) {
     348           0 :                 FRELE(fp, p);
     349           0 :                 return (EBADF);
     350             :         }
     351           0 :         if (old == new) {
     352             :                 /*
     353             :                  * NOTE! This doesn't clear the close-on-exec flag. This might
     354             :                  * or might not be the intended behavior from the start, but
     355             :                  * this is what everyone else does.
     356             :                  */
     357           0 :                 *retval = new;
     358           0 :                 FRELE(fp, p);
     359           0 :                 return (0);
     360             :         }
     361           0 :         fdplock(fdp);
     362           0 :         if (new >= fdp->fd_nfiles) {
     363           0 :                 if ((error = fdalloc(p, new, &i)) != 0) {
     364           0 :                         FRELE(fp, p);
     365           0 :                         if (error == ENOSPC) {
     366           0 :                                 fdexpand(p);
     367           0 :                                 fdpunlock(fdp);
     368           0 :                                 goto restart;
     369             :                         }
     370             :                         goto out;
     371             :                 }
     372           0 :                 if (new != i)
     373           0 :                         panic("dup2: fdalloc");
     374           0 :                 fd_unused(fdp, new);
     375           0 :         }
     376             :         /* No need for FRELE(), finishdup() uses current ref. */
     377           0 :         error = finishdup(p, fp, old, new, retval, 1);
     378           0 :         if (!error && flags & O_CLOEXEC)
     379           0 :                 fdp->fd_ofileflags[new] |= UF_EXCLOSE;
     380             : 
     381             : out:
     382           0 :         fdpunlock(fdp);
     383           0 :         return (error);
     384           0 : }
     385             : 
     386             : /*
     387             :  * The file control system call.
     388             :  */
     389             : int
     390           0 : sys_fcntl(struct proc *p, void *v, register_t *retval)
     391             : {
     392             :         struct sys_fcntl_args /* {
     393             :                 syscallarg(int) fd;
     394             :                 syscallarg(int) cmd;
     395             :                 syscallarg(void *) arg;
     396           0 :         } */ *uap = v;
     397           0 :         int fd = SCARG(uap, fd);
     398           0 :         struct filedesc *fdp = p->p_fd;
     399             :         struct file *fp, *fp2;
     400             :         struct vnode *vp;
     401           0 :         int i, tmp, newmin, flg = F_POSIX;
     402           0 :         struct flock fl;
     403             :         int error = 0;
     404             : 
     405           0 :         error = pledge_fcntl(p, SCARG(uap, cmd));
     406           0 :         if (error)
     407           0 :                 return (error);
     408             : 
     409             : restart:
     410           0 :         if ((fp = fd_getfile(fdp, fd)) == NULL)
     411           0 :                 return (EBADF);
     412           0 :         switch (SCARG(uap, cmd)) {
     413             : 
     414             :         case F_DUPFD:
     415             :         case F_DUPFD_CLOEXEC:
     416           0 :                 newmin = (long)SCARG(uap, arg);
     417           0 :                 if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
     418           0 :                     (u_int)newmin >= maxfiles) {
     419             :                         error = EINVAL;
     420           0 :                         break;
     421             :                 }
     422           0 :                 fdplock(fdp);
     423           0 :                 if ((error = fdalloc(p, newmin, &i)) != 0) {
     424           0 :                         FRELE(fp, p);
     425           0 :                         if (error == ENOSPC) {
     426           0 :                                 fdexpand(p);
     427           0 :                                 fdpunlock(fdp);
     428           0 :                                 goto restart;
     429             :                         }
     430             :                 } else {
     431             :                         /* No need for FRELE(), finishdup() uses current ref. */
     432           0 :                         error = finishdup(p, fp, fd, i, retval, 0);
     433             : 
     434           0 :                         if (!error && SCARG(uap, cmd) == F_DUPFD_CLOEXEC)
     435           0 :                                 fdp->fd_ofileflags[i] |= UF_EXCLOSE;
     436             :                 }
     437             : 
     438           0 :                 fdpunlock(fdp);
     439           0 :                 return (error);
     440             : 
     441             :         case F_GETFD:
     442           0 :                 fdplock(fdp);
     443           0 :                 *retval = fdp->fd_ofileflags[fd] & UF_EXCLOSE ? 1 : 0;
     444           0 :                 fdpunlock(fdp);
     445           0 :                 break;
     446             : 
     447             :         case F_SETFD:
     448           0 :                 fdplock(fdp);
     449           0 :                 if ((long)SCARG(uap, arg) & 1)
     450           0 :                         fdp->fd_ofileflags[fd] |= UF_EXCLOSE;
     451             :                 else
     452           0 :                         fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE;
     453           0 :                 fdpunlock(fdp);
     454           0 :                 break;
     455             : 
     456             :         case F_GETFL:
     457           0 :                 *retval = OFLAGS(fp->f_flag);
     458           0 :                 break;
     459             : 
     460             :         case F_ISATTY:
     461           0 :                 vp = fp->f_data;
     462           0 :                 if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
     463           0 :                         *retval = 1;
     464             :                 else {
     465           0 :                         *retval = 0;
     466             :                         error = ENOTTY;
     467             :                 }
     468             :                 break;
     469             : 
     470             :         case F_SETFL:
     471           0 :                 fp->f_flag &= ~FCNTLFLAGS;
     472           0 :                 fp->f_flag |= FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS;
     473           0 :                 tmp = fp->f_flag & FNONBLOCK;
     474           0 :                 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
     475           0 :                 if (error)
     476             :                         break;
     477           0 :                 tmp = fp->f_flag & FASYNC;
     478           0 :                 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
     479           0 :                 if (!error)
     480             :                         break;
     481           0 :                 fp->f_flag &= ~FNONBLOCK;
     482           0 :                 tmp = 0;
     483           0 :                 (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
     484           0 :                 break;
     485             : 
     486             :         case F_GETOWN:
     487           0 :                 tmp = 0;
     488           0 :                 error = (*fp->f_ops->fo_ioctl)
     489             :                         (fp, TIOCGPGRP, (caddr_t)&tmp, p);
     490           0 :                 *retval = -tmp;
     491           0 :                 break;
     492             : 
     493             :         case F_SETOWN:
     494           0 :                 tmp = (long)SCARG(uap, arg);
     495           0 :                 if (fp->f_type == DTYPE_SOCKET || fp->f_type == DTYPE_PIPE) {
     496             :                         /* nothing */
     497           0 :                 } else if (tmp <= 0) {
     498           0 :                         tmp = -tmp;
     499           0 :                 } else {
     500           0 :                         struct process *pr1 = prfind(tmp);
     501           0 :                         if (pr1 == 0) {
     502             :                                 error = ESRCH;
     503           0 :                                 break;
     504             :                         }
     505           0 :                         tmp = pr1->ps_pgrp->pg_id;
     506           0 :                 }
     507           0 :                 error = ((*fp->f_ops->fo_ioctl)
     508             :                         (fp, TIOCSPGRP, (caddr_t)&tmp, p));
     509           0 :                 break;
     510             : 
     511             :         case F_SETLKW:
     512           0 :                 flg |= F_WAIT;
     513             :                 /* FALLTHROUGH */
     514             : 
     515             :         case F_SETLK:
     516           0 :                 error = pledge_flock(p);
     517           0 :                 if (error != 0)
     518             :                         break;
     519             : 
     520           0 :                 if (fp->f_type != DTYPE_VNODE) {
     521             :                         error = EBADF;
     522           0 :                         break;
     523             :                 }
     524           0 :                 vp = fp->f_data;
     525             :                 /* Copy in the lock structure */
     526           0 :                 error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
     527             :                     sizeof (fl));
     528           0 :                 if (error)
     529             :                         break;
     530           0 :                 if (fl.l_whence == SEEK_CUR) {
     531           0 :                         if (fl.l_start == 0 && fl.l_len < 0) {
     532             :                                 /* lockf(3) compliance hack */
     533           0 :                                 fl.l_len = -fl.l_len;
     534           0 :                                 fl.l_start = fp->f_offset - fl.l_len;
     535           0 :                         } else
     536           0 :                                 fl.l_start += fp->f_offset;
     537             :                 }
     538           0 :                 switch (fl.l_type) {
     539             : 
     540             :                 case F_RDLCK:
     541           0 :                         if ((fp->f_flag & FREAD) == 0) {
     542             :                                 error = EBADF;
     543           0 :                                 goto out;
     544             :                         }
     545           0 :                         atomic_setbits_int(&fdp->fd_flags, FD_ADVLOCK);
     546           0 :                         error = VOP_ADVLOCK(vp, fdp, F_SETLK, &fl, flg);
     547           0 :                         break;
     548             : 
     549             :                 case F_WRLCK:
     550           0 :                         if ((fp->f_flag & FWRITE) == 0) {
     551             :                                 error = EBADF;
     552           0 :                                 goto out;
     553             :                         }
     554           0 :                         atomic_setbits_int(&fdp->fd_flags, FD_ADVLOCK);
     555           0 :                         error = VOP_ADVLOCK(vp, fdp, F_SETLK, &fl, flg);
     556           0 :                         break;
     557             : 
     558             :                 case F_UNLCK:
     559           0 :                         error = VOP_ADVLOCK(vp, fdp, F_UNLCK, &fl, F_POSIX);
     560           0 :                         goto out;
     561             : 
     562             :                 default:
     563             :                         error = EINVAL;
     564           0 :                         goto out;
     565             :                 }
     566             : 
     567           0 :                 fp2 = fd_getfile(fdp, fd);
     568           0 :                 if (fp != fp2) {
     569             :                         /*
     570             :                          * We have lost the race with close() or dup2();
     571             :                          * unlock, pretend that we've won the race and that
     572             :                          * lock had been removed by close()
     573             :                          */
     574           0 :                         fl.l_whence = SEEK_SET;
     575           0 :                         fl.l_start = 0;
     576           0 :                         fl.l_len = 0;
     577           0 :                         VOP_ADVLOCK(vp, fdp, F_UNLCK, &fl, F_POSIX);
     578           0 :                         fl.l_type = F_UNLCK;
     579           0 :                 }
     580           0 :                 if (fp2 != NULL)
     581           0 :                         FRELE(fp2, p);
     582             :                 goto out;
     583             : 
     584             : 
     585             :         case F_GETLK:
     586           0 :                 error = pledge_flock(p);
     587           0 :                 if (error != 0)
     588             :                         break;
     589             : 
     590           0 :                 if (fp->f_type != DTYPE_VNODE) {
     591             :                         error = EBADF;
     592           0 :                         break;
     593             :                 }
     594           0 :                 vp = fp->f_data;
     595             :                 /* Copy in the lock structure */
     596           0 :                 error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
     597             :                     sizeof (fl));
     598           0 :                 if (error)
     599             :                         break;
     600           0 :                 if (fl.l_whence == SEEK_CUR) {
     601           0 :                         if (fl.l_start == 0 && fl.l_len < 0) {
     602             :                                 /* lockf(3) compliance hack */
     603           0 :                                 fl.l_len = -fl.l_len;
     604           0 :                                 fl.l_start = fp->f_offset - fl.l_len;
     605           0 :                         } else
     606           0 :                                 fl.l_start += fp->f_offset;
     607             :                 }
     608           0 :                 if (fl.l_type != F_RDLCK &&
     609           0 :                     fl.l_type != F_WRLCK &&
     610           0 :                     fl.l_type != F_UNLCK &&
     611           0 :                     fl.l_type != 0) {
     612             :                         error = EINVAL;
     613           0 :                         break;
     614             :                 }
     615           0 :                 error = VOP_ADVLOCK(vp, fdp, F_GETLK, &fl, F_POSIX);
     616           0 :                 if (error)
     617             :                         break;
     618           0 :                 error = (copyout((caddr_t)&fl, (caddr_t)SCARG(uap, arg),
     619             :                     sizeof (fl)));
     620           0 :                 break;
     621             : 
     622             :         default:
     623             :                 error = EINVAL;
     624           0 :                 break;
     625             :         }
     626             : out:
     627           0 :         FRELE(fp, p);
     628           0 :         return (error); 
     629           0 : }
     630             : 
     631             : /*
     632             :  * Common code for dup, dup2, and fcntl(F_DUPFD).
     633             :  */
     634             : int
     635           0 : finishdup(struct proc *p, struct file *fp, int old, int new,
     636             :     register_t *retval, int dup2)
     637             : {
     638             :         struct file *oldfp;
     639           0 :         struct filedesc *fdp = p->p_fd;
     640             : 
     641           0 :         fdpassertlocked(fdp);
     642           0 :         KASSERT(fp->f_iflags & FIF_INSERTED);
     643             : 
     644           0 :         if (fp->f_count >= FDUP_MAX_COUNT) {
     645           0 :                 FRELE(fp, p);
     646           0 :                 return (EDEADLK);
     647             :         }
     648             : 
     649           0 :         oldfp = fd_getfile(fdp, new);
     650           0 :         if (dup2 && oldfp == NULL) {
     651           0 :                 if (fd_inuse(fdp, new)) {
     652           0 :                         FRELE(fp, p);
     653           0 :                         return (EBUSY);
     654             :                 }
     655           0 :                 fd_used(fdp, new);
     656           0 :         }
     657             : 
     658             :         /*
     659             :          * Use `fd_fplock' to synchronize with fd_getfile() so that
     660             :          * the function no longer creates a new reference to the old file.
     661             :          */
     662           0 :         mtx_enter(&fdp->fd_fplock);
     663           0 :         fdp->fd_ofiles[new] = fp;
     664           0 :         mtx_leave(&fdp->fd_fplock);
     665             : 
     666           0 :         fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] & ~UF_EXCLOSE;
     667           0 :         *retval = new;
     668             : 
     669           0 :         if (oldfp != NULL) {
     670           0 :                 knote_fdclose(p, new);
     671           0 :                 closef(oldfp, p);
     672           0 :         }
     673             : 
     674           0 :         return (0);
     675           0 : }
     676             : 
     677             : void
     678           0 : fdinsert(struct filedesc *fdp, int fd, int flags, struct file *fp)
     679             : {
     680             :         struct file *fq;
     681             : 
     682           0 :         fdpassertlocked(fdp);
     683             : 
     684           0 :         mtx_enter(&fhdlk);
     685           0 :         if ((fp->f_iflags & FIF_INSERTED) == 0) {
     686           0 :                 fp->f_iflags |= FIF_INSERTED;
     687           0 :                 if ((fq = fdp->fd_ofiles[0]) != NULL) {
     688           0 :                         LIST_INSERT_AFTER(fq, fp, f_list);
     689           0 :                 } else {
     690           0 :                         LIST_INSERT_HEAD(&filehead, fp, f_list);
     691             :                 }
     692             :         }
     693           0 :         mtx_leave(&fhdlk);
     694             : 
     695           0 :         mtx_enter(&fdp->fd_fplock);
     696           0 :         KASSERT(fdp->fd_ofiles[fd] == NULL);
     697           0 :         fdp->fd_ofiles[fd] = fp;
     698           0 :         mtx_leave(&fdp->fd_fplock);
     699             : 
     700           0 :         fdp->fd_ofileflags[fd] |= (flags & UF_EXCLOSE);
     701           0 : }
     702             : 
     703             : void
     704           0 : fdremove(struct filedesc *fdp, int fd)
     705             : {
     706           0 :         fdpassertlocked(fdp);
     707             : 
     708             :         /*
     709             :          * Use `fd_fplock' to synchronize with fd_getfile() so that
     710             :          * the function no longer creates a new reference to the file.
     711             :          */
     712           0 :         mtx_enter(&fdp->fd_fplock);
     713           0 :         fdp->fd_ofiles[fd] = NULL;
     714           0 :         mtx_leave(&fdp->fd_fplock);
     715             : 
     716           0 :         fdp->fd_ofileflags[fd] = 0;
     717             : 
     718           0 :         fd_unused(fdp, fd);
     719           0 : }
     720             : 
     721             : int
     722           0 : fdrelease(struct proc *p, int fd)
     723             : {
     724           0 :         struct filedesc *fdp = p->p_fd;
     725             :         struct file *fp;
     726             :         int error;
     727             : 
     728           0 :         fdpassertlocked(fdp);
     729             : 
     730           0 :         fp = fd_getfile(fdp, fd);
     731           0 :         if (fp == NULL)
     732           0 :                 return (EBADF);
     733           0 :         fdremove(fdp, fd);
     734           0 :         knote_fdclose(p, fd);
     735           0 :         fdpunlock(fdp);
     736           0 :         error = closef(fp, p);
     737           0 :         fdplock(fdp);
     738           0 :         return error;
     739           0 : }
     740             : 
     741             : /*
     742             :  * Close a file descriptor.
     743             :  */
     744             : int
     745           0 : sys_close(struct proc *p, void *v, register_t *retval)
     746             : {
     747             :         struct sys_close_args /* {
     748             :                 syscallarg(int) fd;
     749           0 :         } */ *uap = v;
     750           0 :         int fd = SCARG(uap, fd), error;
     751           0 :         struct filedesc *fdp = p->p_fd;
     752             : 
     753           0 :         fdplock(fdp);
     754           0 :         error = fdrelease(p, fd);
     755           0 :         fdpunlock(fdp);
     756             : 
     757           0 :         return (error);
     758             : }
     759             : 
     760             : /*
     761             :  * Return status information about a file descriptor.
     762             :  */
     763             : int
     764           0 : sys_fstat(struct proc *p, void *v, register_t *retval)
     765             : {
     766             :         struct sys_fstat_args /* {
     767             :                 syscallarg(int) fd;
     768             :                 syscallarg(struct stat *) sb;
     769           0 :         } */ *uap = v;
     770           0 :         int fd = SCARG(uap, fd);
     771           0 :         struct filedesc *fdp = p->p_fd;
     772             :         struct file *fp;
     773           0 :         struct stat ub;
     774             :         int error;
     775             : 
     776           0 :         if ((fp = fd_getfile(fdp, fd)) == NULL)
     777           0 :                 return (EBADF);
     778           0 :         error = (*fp->f_ops->fo_stat)(fp, &ub, p);
     779           0 :         FRELE(fp, p);
     780           0 :         if (error == 0) {
     781             :                 /* 
     782             :                  * Don't let non-root see generation numbers
     783             :                  * (for NFS security)
     784             :                  */
     785           0 :                 if (suser(p))
     786           0 :                         ub.st_gen = 0;
     787           0 :                 error = copyout((caddr_t)&ub, (caddr_t)SCARG(uap, sb),
     788             :                     sizeof (ub));
     789           0 :         }
     790             : #ifdef KTRACE
     791           0 :         if (error == 0 && KTRPOINT(p, KTR_STRUCT))
     792           0 :                 ktrstat(p, &ub);
     793             : #endif
     794           0 :         return (error);
     795           0 : }
     796             : 
     797             : /*
     798             :  * Return pathconf information about a file descriptor.
     799             :  */
     800             : int
     801           0 : sys_fpathconf(struct proc *p, void *v, register_t *retval)
     802             : {
     803             :         struct sys_fpathconf_args /* {
     804             :                 syscallarg(int) fd;
     805             :                 syscallarg(int) name;
     806           0 :         } */ *uap = v;
     807           0 :         int fd = SCARG(uap, fd);
     808           0 :         struct filedesc *fdp = p->p_fd;
     809             :         struct file *fp;
     810             :         struct vnode *vp;
     811             :         int error;
     812             : 
     813           0 :         if ((fp = fd_getfile(fdp, fd)) == NULL)
     814           0 :                 return (EBADF);
     815           0 :         switch (fp->f_type) {
     816             :         case DTYPE_PIPE:
     817             :         case DTYPE_SOCKET:
     818           0 :                 if (SCARG(uap, name) != _PC_PIPE_BUF) {
     819             :                         error = EINVAL;
     820           0 :                         break;
     821             :                 }
     822           0 :                 *retval = PIPE_BUF;
     823             :                 error = 0;
     824           0 :                 break;
     825             : 
     826             :         case DTYPE_VNODE:
     827           0 :                 vp = fp->f_data;
     828           0 :                 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
     829           0 :                 error = VOP_PATHCONF(vp, SCARG(uap, name), retval);
     830           0 :                 VOP_UNLOCK(vp);
     831           0 :                 break;
     832             : 
     833             :         default:
     834             :                 error = EOPNOTSUPP;
     835           0 :                 break;
     836             :         }
     837           0 :         FRELE(fp, p);
     838           0 :         return (error);
     839           0 : }
     840             : 
     841             : /*
     842             :  * Allocate a file descriptor for the process.
     843             :  */
     844             : int
     845           0 : fdalloc(struct proc *p, int want, int *result)
     846             : {
     847           0 :         struct filedesc *fdp = p->p_fd;
     848             :         int lim, last, i;
     849             :         u_int new, off;
     850             : 
     851           0 :         fdpassertlocked(fdp);
     852             : 
     853             :         /*
     854             :          * Search for a free descriptor starting at the higher
     855             :          * of want or fd_freefile.  If that fails, consider
     856             :          * expanding the ofile array.
     857             :          */
     858             : restart:
     859           0 :         lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
     860           0 :         last = min(fdp->fd_nfiles, lim);
     861           0 :         if ((i = want) < fdp->fd_freefile)
     862           0 :                 i = fdp->fd_freefile;
     863           0 :         off = i >> NDENTRYSHIFT;
     864           0 :         new = find_next_zero(fdp->fd_himap, off,
     865           0 :             (last + NDENTRIES - 1) >> NDENTRYSHIFT);
     866           0 :         if (new != -1) {
     867           0 :                 i = find_next_zero(&fdp->fd_lomap[new], 
     868           0 :                                    new > off ? 0 : i & NDENTRYMASK,
     869             :                                    NDENTRIES);
     870           0 :                 if (i == -1) {
     871             :                         /*
     872             :                          * Free file descriptor in this block was
     873             :                          * below want, try again with higher want.
     874             :                          */
     875           0 :                         want = (new + 1) << NDENTRYSHIFT;
     876           0 :                         goto restart;
     877             :                 }
     878           0 :                 i += (new << NDENTRYSHIFT);
     879           0 :                 if (i < last) {
     880           0 :                         fd_used(fdp, i);
     881           0 :                         if (want <= fdp->fd_freefile)
     882           0 :                                 fdp->fd_freefile = i;
     883           0 :                         *result = i;
     884           0 :                         fdp->fd_ofileflags[i] = 0;
     885           0 :                         if (ISSET(p->p_p->ps_flags, PS_PLEDGE))
     886           0 :                                 fdp->fd_ofileflags[i] |= UF_PLEDGED;
     887           0 :                         return (0);
     888             :                 }
     889             :         }
     890           0 :         if (fdp->fd_nfiles >= lim)
     891           0 :                 return (EMFILE);
     892             : 
     893           0 :         return (ENOSPC);
     894           0 : }
     895             : 
     896             : void
     897           0 : fdexpand(struct proc *p)
     898             : {
     899           0 :         struct filedesc *fdp = p->p_fd;
     900             :         int nfiles, oldnfiles;
     901             :         size_t copylen;
     902             :         struct file **newofile, **oldofile;
     903             :         char *newofileflags;
     904             :         u_int *newhimap, *newlomap;
     905             : 
     906           0 :         fdpassertlocked(fdp);
     907             : 
     908           0 :         oldnfiles = fdp->fd_nfiles;
     909           0 :         oldofile = fdp->fd_ofiles;
     910             : 
     911             :         /*
     912             :          * No space in current array.
     913             :          */
     914           0 :         if (fdp->fd_nfiles < NDEXTENT)
     915           0 :                 nfiles = NDEXTENT;
     916             :         else
     917           0 :                 nfiles = 2 * fdp->fd_nfiles;
     918             : 
     919           0 :         newofile = mallocarray(nfiles, OFILESIZE, M_FILEDESC, M_WAITOK);
     920             :         /*
     921             :          * Allocate all required chunks before calling free(9) to make
     922             :          * sure that ``fd_ofiles'' stays valid if we go to sleep.
     923             :          */
     924           0 :         if (NDHISLOTS(nfiles) > NDHISLOTS(fdp->fd_nfiles)) {
     925           0 :                 newhimap = mallocarray(NDHISLOTS(nfiles), sizeof(u_int),
     926             :                     M_FILEDESC, M_WAITOK);
     927           0 :                 newlomap = mallocarray(NDLOSLOTS(nfiles), sizeof(u_int),
     928             :                     M_FILEDESC, M_WAITOK);
     929           0 :         }
     930           0 :         newofileflags = (char *) &newofile[nfiles];
     931             : 
     932             :         /*
     933             :          * Copy the existing ofile and ofileflags arrays
     934             :          * and zero the new portion of each array.
     935             :          */
     936           0 :         copylen = sizeof(struct file *) * fdp->fd_nfiles;
     937           0 :         memcpy(newofile, fdp->fd_ofiles, copylen);
     938           0 :         memset((char *)newofile + copylen, 0,
     939             :             nfiles * sizeof(struct file *) - copylen);
     940           0 :         copylen = sizeof(char) * fdp->fd_nfiles;
     941           0 :         memcpy(newofileflags, fdp->fd_ofileflags, copylen);
     942           0 :         memset(newofileflags + copylen, 0, nfiles * sizeof(char) - copylen);
     943             : 
     944           0 :         if (NDHISLOTS(nfiles) > NDHISLOTS(fdp->fd_nfiles)) {
     945           0 :                 copylen = NDHISLOTS(fdp->fd_nfiles) * sizeof(u_int);
     946           0 :                 memcpy(newhimap, fdp->fd_himap, copylen);
     947           0 :                 memset((char *)newhimap + copylen, 0,
     948             :                     NDHISLOTS(nfiles) * sizeof(u_int) - copylen);
     949             : 
     950           0 :                 copylen = NDLOSLOTS(fdp->fd_nfiles) * sizeof(u_int);
     951           0 :                 memcpy(newlomap, fdp->fd_lomap, copylen);
     952           0 :                 memset((char *)newlomap + copylen, 0,
     953             :                     NDLOSLOTS(nfiles) * sizeof(u_int) - copylen);
     954             : 
     955           0 :                 if (NDHISLOTS(fdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
     956           0 :                         free(fdp->fd_himap, M_FILEDESC,
     957           0 :                             NDHISLOTS(fdp->fd_nfiles) * sizeof(u_int));
     958           0 :                         free(fdp->fd_lomap, M_FILEDESC,
     959           0 :                             NDLOSLOTS(fdp->fd_nfiles) * sizeof(u_int));
     960           0 :                 }
     961           0 :                 fdp->fd_himap = newhimap;
     962           0 :                 fdp->fd_lomap = newlomap;
     963           0 :         }
     964             : 
     965           0 :         mtx_enter(&fdp->fd_fplock);
     966           0 :         fdp->fd_ofiles = newofile;
     967           0 :         mtx_leave(&fdp->fd_fplock);
     968             : 
     969           0 :         fdp->fd_ofileflags = newofileflags;
     970           0 :         fdp->fd_nfiles = nfiles;
     971             : 
     972           0 :         if (oldnfiles > NDFILE)
     973           0 :                 free(oldofile, M_FILEDESC, oldnfiles * OFILESIZE);
     974           0 : }
     975             : 
     976             : /*
     977             :  * Create a new open file structure and allocate
     978             :  * a file descriptor for the process that refers to it.
     979             :  */
     980             : int
     981           0 : falloc(struct proc *p, struct file **resultfp, int *resultfd)
     982             : {
     983             :         struct file *fp;
     984           0 :         int error, i;
     985             : 
     986           0 :         KASSERT(resultfp != NULL);
     987           0 :         KASSERT(resultfd != NULL);
     988             : 
     989           0 :         fdpassertlocked(p->p_fd);
     990             : restart:
     991           0 :         if ((error = fdalloc(p, 0, &i)) != 0) {
     992           0 :                 if (error == ENOSPC) {
     993           0 :                         fdexpand(p);
     994           0 :                         goto restart;
     995             :                 }
     996           0 :                 return (error);
     997             :         }
     998             : 
     999           0 :         fp = fnew(p);
    1000           0 :         if (fp == NULL) {
    1001           0 :                 fd_unused(p->p_fd, i);
    1002           0 :                 return (ENFILE);
    1003             :         }
    1004             : 
    1005           0 :         FREF(fp);
    1006           0 :         *resultfp = fp;
    1007           0 :         *resultfd = i;
    1008             : 
    1009           0 :         return (0);
    1010           0 : }
    1011             : 
    1012             : struct file *
    1013           0 : fnew(struct proc *p)
    1014             : {
    1015             :         struct file *fp;
    1016             :         int nfiles;
    1017             : 
    1018           0 :         nfiles = atomic_inc_int_nv(&numfiles);
    1019           0 :         if (nfiles > maxfiles) {
    1020           0 :                 atomic_dec_int(&numfiles);
    1021           0 :                 tablefull("file");
    1022           0 :                 return (NULL);
    1023             :         }
    1024             : 
    1025           0 :         fp = pool_get(&file_pool, PR_WAITOK|PR_ZERO);
    1026             :         /*
    1027             :          * We need to block interrupts as long as `f_mtx' is being taken
    1028             :          * with and without the KERNEL_LOCK().
    1029             :          */
    1030           0 :         mtx_init(&fp->f_mtx, IPL_MPFLOOR);
    1031           0 :         fp->f_count = 1;
    1032           0 :         fp->f_cred = p->p_ucred;
    1033           0 :         crhold(fp->f_cred);
    1034             : 
    1035           0 :         return (fp);
    1036           0 : }
    1037             : 
    1038             : /*
    1039             :  * Build a new filedesc structure.
    1040             :  */
    1041             : struct filedesc *
    1042           0 : fdinit(void)
    1043             : {
    1044             :         struct filedesc0 *newfdp;
    1045             : 
    1046           0 :         newfdp = pool_get(&fdesc_pool, PR_WAITOK|PR_ZERO);
    1047           0 :         rw_init(&newfdp->fd_fd.fd_lock, "fdlock");
    1048           0 :         mtx_init(&newfdp->fd_fd.fd_fplock, IPL_MPFLOOR);
    1049             : 
    1050             :         /* Create the file descriptor table. */
    1051           0 :         newfdp->fd_fd.fd_refcnt = 1;
    1052           0 :         newfdp->fd_fd.fd_cmask = S_IWGRP|S_IWOTH;
    1053           0 :         newfdp->fd_fd.fd_ofiles = newfdp->fd_dfiles;
    1054           0 :         newfdp->fd_fd.fd_ofileflags = newfdp->fd_dfileflags;
    1055           0 :         newfdp->fd_fd.fd_nfiles = NDFILE;
    1056           0 :         newfdp->fd_fd.fd_himap = newfdp->fd_dhimap;
    1057           0 :         newfdp->fd_fd.fd_lomap = newfdp->fd_dlomap;
    1058             : 
    1059           0 :         newfdp->fd_fd.fd_freefile = 0;
    1060           0 :         newfdp->fd_fd.fd_lastfile = 0;
    1061             : 
    1062           0 :         return (&newfdp->fd_fd);
    1063             : }
    1064             : 
    1065             : /*
    1066             :  * Share a filedesc structure.
    1067             :  */
    1068             : struct filedesc *
    1069           0 : fdshare(struct process *pr)
    1070             : {
    1071           0 :         pr->ps_fd->fd_refcnt++;
    1072           0 :         return (pr->ps_fd);
    1073             : }
    1074             : 
    1075             : /*
    1076             :  * Copy a filedesc structure.
    1077             :  */
    1078             : struct filedesc *
    1079           0 : fdcopy(struct process *pr)
    1080             : {
    1081           0 :         struct filedesc *newfdp, *fdp = pr->ps_fd;
    1082             :         int i;
    1083             : 
    1084           0 :         newfdp = fdinit();
    1085             : 
    1086           0 :         fdplock(fdp);
    1087           0 :         if (fdp->fd_cdir) {
    1088           0 :                 vref(fdp->fd_cdir);
    1089           0 :                 newfdp->fd_cdir = fdp->fd_cdir;
    1090           0 :         }
    1091           0 :         if (fdp->fd_rdir) {
    1092           0 :                 vref(fdp->fd_rdir);
    1093           0 :                 newfdp->fd_rdir = fdp->fd_rdir;
    1094           0 :         }
    1095             : 
    1096             :         /*
    1097             :          * If the number of open files fits in the internal arrays
    1098             :          * of the open file structure, use them, otherwise allocate
    1099             :          * additional memory for the number of descriptors currently
    1100             :          * in use.
    1101             :          */
    1102           0 :         if (fdp->fd_lastfile >= NDFILE) {
    1103             :                 /*
    1104             :                  * Compute the smallest multiple of NDEXTENT needed
    1105             :                  * for the file descriptors currently in use,
    1106             :                  * allowing the table to shrink.
    1107             :                  */
    1108           0 :                 i = fdp->fd_nfiles;
    1109           0 :                 while (i >= 2 * NDEXTENT && i > fdp->fd_lastfile * 2)
    1110           0 :                         i /= 2;
    1111           0 :                 newfdp->fd_ofiles = mallocarray(i, OFILESIZE, M_FILEDESC,
    1112             :                     M_WAITOK | M_ZERO);
    1113           0 :                 newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
    1114           0 :                 newfdp->fd_nfiles = i;
    1115           0 :         }
    1116           0 :         if (NDHISLOTS(newfdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
    1117           0 :                 newfdp->fd_himap = mallocarray(NDHISLOTS(newfdp->fd_nfiles),
    1118             :                     sizeof(u_int), M_FILEDESC, M_WAITOK | M_ZERO);
    1119           0 :                 newfdp->fd_lomap = mallocarray(NDLOSLOTS(newfdp->fd_nfiles),
    1120             :                     sizeof(u_int), M_FILEDESC, M_WAITOK | M_ZERO);
    1121           0 :         }
    1122           0 :         newfdp->fd_freefile = fdp->fd_freefile;
    1123           0 :         newfdp->fd_flags = fdp->fd_flags;
    1124           0 :         newfdp->fd_cmask = fdp->fd_cmask;
    1125             : 
    1126           0 :         for (i = 0; i <= fdp->fd_lastfile; i++) {
    1127           0 :                 struct file *fp = fdp->fd_ofiles[i];
    1128             : 
    1129           0 :                 if (fp != NULL) {
    1130             :                         /*
    1131             :                          * XXX Gruesome hack. If count gets too high, fail
    1132             :                          * to copy an fd, since fdcopy()'s callers do not
    1133             :                          * permit it to indicate failure yet.
    1134             :                          * Meanwhile, kqueue files have to be
    1135             :                          * tied to the process that opened them to enforce
    1136             :                          * their internal consistency, so close them here.
    1137             :                          */
    1138           0 :                         if (fp->f_count >= FDUP_MAX_COUNT ||
    1139           0 :                             fp->f_type == DTYPE_KQUEUE) {
    1140           0 :                                 if (i < newfdp->fd_freefile)
    1141           0 :                                         newfdp->fd_freefile = i;
    1142           0 :                                 continue;
    1143             :                         }
    1144             : 
    1145           0 :                         FREF(fp);
    1146           0 :                         newfdp->fd_ofiles[i] = fp;
    1147           0 :                         newfdp->fd_ofileflags[i] = fdp->fd_ofileflags[i];
    1148           0 :                         fd_used(newfdp, i);
    1149           0 :                 }
    1150           0 :         }
    1151           0 :         fdpunlock(fdp);
    1152             : 
    1153           0 :         return (newfdp);
    1154             : }
    1155             : 
    1156             : /*
    1157             :  * Release a filedesc structure.
    1158             :  */
    1159             : void
    1160           0 : fdfree(struct proc *p)
    1161             : {
    1162           0 :         struct filedesc *fdp = p->p_fd;
    1163             :         struct file *fp;
    1164             :         int fd;
    1165             : 
    1166           0 :         if (--fdp->fd_refcnt > 0)
    1167           0 :                 return;
    1168           0 :         for (fd = 0; fd <= fdp->fd_lastfile; fd++) {
    1169           0 :                 fp = fdp->fd_ofiles[fd];
    1170           0 :                 if (fp != NULL) {
    1171           0 :                         fdp->fd_ofiles[fd] = NULL;
    1172           0 :                         knote_fdclose(p, fd);
    1173             :                          /* closef() expects a refcount of 2 */
    1174           0 :                         FREF(fp);
    1175           0 :                         (void) closef(fp, p);
    1176           0 :                 }
    1177             :         }
    1178           0 :         p->p_fd = NULL;
    1179           0 :         if (fdp->fd_nfiles > NDFILE)
    1180           0 :                 free(fdp->fd_ofiles, M_FILEDESC, fdp->fd_nfiles * OFILESIZE);
    1181           0 :         if (NDHISLOTS(fdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
    1182           0 :                 free(fdp->fd_himap, M_FILEDESC,
    1183           0 :                     NDHISLOTS(fdp->fd_nfiles) * sizeof(u_int));
    1184           0 :                 free(fdp->fd_lomap, M_FILEDESC,
    1185           0 :                     NDLOSLOTS(fdp->fd_nfiles) * sizeof(u_int));
    1186           0 :         }
    1187           0 :         if (fdp->fd_cdir)
    1188           0 :                 vrele(fdp->fd_cdir);
    1189           0 :         if (fdp->fd_rdir)
    1190           0 :                 vrele(fdp->fd_rdir);
    1191           0 :         pool_put(&fdesc_pool, fdp);
    1192           0 : }
    1193             : 
    1194             : /*
    1195             :  * Internal form of close.
    1196             :  * Decrement reference count on file structure.
    1197             :  * Note: p may be NULL when closing a file
    1198             :  * that was being passed in a message.
    1199             :  *
    1200             :  * The fp must have its usecount bumped and will be FRELEd here.
    1201             :  */
    1202             : int
    1203           0 : closef(struct file *fp, struct proc *p)
    1204             : {
    1205             :         struct filedesc *fdp;
    1206             : 
    1207           0 :         if (fp == NULL)
    1208           0 :                 return (0);
    1209             : 
    1210           0 :         KASSERTMSG(fp->f_count >= 2, "count (%u) < 2", fp->f_count);
    1211             : 
    1212           0 :         atomic_dec_int(&fp->f_count);
    1213             : 
    1214             :         /*
    1215             :          * POSIX record locking dictates that any close releases ALL
    1216             :          * locks owned by this process.  This is handled by setting
    1217             :          * a flag in the unlock to free ONLY locks obeying POSIX
    1218             :          * semantics, and not to free BSD-style file locks.
    1219             :          * If the descriptor was in a message, POSIX-style locks
    1220             :          * aren't passed with the descriptor.
    1221             :          */
    1222             : 
    1223           0 :         if (p && ((fdp = p->p_fd) != NULL) &&
    1224           0 :             (fdp->fd_flags & FD_ADVLOCK) &&
    1225           0 :             fp->f_type == DTYPE_VNODE) {
    1226           0 :                 struct vnode *vp = fp->f_data;
    1227           0 :                 struct flock lf;
    1228             : 
    1229           0 :                 lf.l_whence = SEEK_SET;
    1230           0 :                 lf.l_start = 0;
    1231           0 :                 lf.l_len = 0;
    1232           0 :                 lf.l_type = F_UNLCK;
    1233           0 :                 (void) VOP_ADVLOCK(vp, fdp, F_UNLCK, &lf, F_POSIX);
    1234           0 :         }
    1235             : 
    1236           0 :         return (FRELE(fp, p));
    1237           0 : }
    1238             : 
    1239             : int
    1240           0 : fdrop(struct file *fp, struct proc *p)
    1241             : {
    1242             :         int error;
    1243             : 
    1244           0 :         KASSERTMSG(fp->f_count == 0, "count (%u) != 0", fp->f_count);
    1245             : 
    1246           0 :         mtx_enter(&fhdlk);
    1247           0 :         if (fp->f_iflags & FIF_INSERTED)
    1248           0 :                 LIST_REMOVE(fp, f_list);
    1249           0 :         mtx_leave(&fhdlk);
    1250             : 
    1251           0 :         if (fp->f_ops)
    1252           0 :                 error = (*fp->f_ops->fo_close)(fp, p);
    1253             :         else
    1254             :                 error = 0;
    1255             : 
    1256           0 :         crfree(fp->f_cred);
    1257           0 :         atomic_dec_int(&numfiles);
    1258           0 :         pool_put(&file_pool, fp);
    1259             : 
    1260           0 :         return (error);
    1261             : }
    1262             : 
    1263             : /*
    1264             :  * Apply an advisory lock on a file descriptor.
    1265             :  *
    1266             :  * Just attempt to get a record lock of the requested type on
    1267             :  * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
    1268             :  */
    1269             : int
    1270           0 : sys_flock(struct proc *p, void *v, register_t *retval)
    1271             : {
    1272             :         struct sys_flock_args /* {
    1273             :                 syscallarg(int) fd;
    1274             :                 syscallarg(int) how;
    1275           0 :         } */ *uap = v;
    1276           0 :         int fd = SCARG(uap, fd);
    1277           0 :         int how = SCARG(uap, how);
    1278           0 :         struct filedesc *fdp = p->p_fd;
    1279             :         struct file *fp;
    1280             :         struct vnode *vp;
    1281           0 :         struct flock lf;
    1282             :         int error;
    1283             : 
    1284           0 :         if ((fp = fd_getfile(fdp, fd)) == NULL)
    1285           0 :                 return (EBADF);
    1286           0 :         if (fp->f_type != DTYPE_VNODE) {
    1287             :                 error = EOPNOTSUPP;
    1288           0 :                 goto out;
    1289             :         }
    1290           0 :         vp = fp->f_data;
    1291           0 :         lf.l_whence = SEEK_SET;
    1292           0 :         lf.l_start = 0;
    1293           0 :         lf.l_len = 0;
    1294           0 :         if (how & LOCK_UN) {
    1295           0 :                 lf.l_type = F_UNLCK;
    1296           0 :                 fp->f_iflags &= ~FIF_HASLOCK;
    1297           0 :                 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
    1298           0 :                 goto out;
    1299             :         }
    1300           0 :         if (how & LOCK_EX)
    1301           0 :                 lf.l_type = F_WRLCK;
    1302           0 :         else if (how & LOCK_SH)
    1303           0 :                 lf.l_type = F_RDLCK;
    1304             :         else {
    1305             :                 error = EINVAL;
    1306           0 :                 goto out;
    1307             :         }
    1308           0 :         fp->f_iflags |= FIF_HASLOCK;
    1309           0 :         if (how & LOCK_NB)
    1310           0 :                 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK);
    1311             :         else
    1312           0 :                 error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT);
    1313             : out:
    1314           0 :         FRELE(fp, p);
    1315           0 :         return (error);
    1316           0 : }
    1317             : 
    1318             : /*
    1319             :  * File Descriptor pseudo-device driver (/dev/fd/).
    1320             :  *
    1321             :  * Opening minor device N dup()s the file (if any) connected to file
    1322             :  * descriptor N belonging to the calling process.  Note that this driver
    1323             :  * consists of only the ``open()'' routine, because all subsequent
    1324             :  * references to this file will be direct to the other driver.
    1325             :  */
    1326             : int
    1327           0 : filedescopen(dev_t dev, int mode, int type, struct proc *p)
    1328             : {
    1329             : 
    1330             :         /*
    1331             :          * XXX Kludge: set curproc->p_dupfd to contain the value of the
    1332             :          * the file descriptor being sought for duplication. The error
    1333             :          * return ensures that the vnode for this device will be released
    1334             :          * by vn_open. Open will detect this special error and take the
    1335             :          * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
    1336             :          * will simply report the error.
    1337             :          */
    1338           0 :         p->p_dupfd = minor(dev);
    1339           0 :         return (ENODEV);
    1340             : }
    1341             : 
    1342             : /*
    1343             :  * Duplicate the specified descriptor to a free descriptor.
    1344             :  */
    1345             : int
    1346           0 : dupfdopen(struct proc *p, int indx, int mode)
    1347             : {
    1348           0 :         struct filedesc *fdp = p->p_fd;
    1349           0 :         int dupfd = p->p_dupfd;
    1350             :         struct file *wfp;
    1351             : 
    1352           0 :         fdpassertlocked(fdp);
    1353             : 
    1354             :         /*
    1355             :          * Assume that the filename was user-specified; applications do
    1356             :          * not tend to open /dev/fd/# when they can just call dup()
    1357             :          */
    1358           0 :         if ((p->p_p->ps_flags & (PS_SUGIDEXEC | PS_SUGID))) {
    1359           0 :                 if (p->p_descfd == 255)
    1360           0 :                         return (EPERM);
    1361           0 :                 if (p->p_descfd != dupfd)
    1362           0 :                         return (EPERM);
    1363             :         }
    1364             : 
    1365             :         /*
    1366             :          * If the to-be-dup'd fd number is greater than the allowed number
    1367             :          * of file descriptors, or the fd to be dup'd has already been
    1368             :          * closed, reject. Note, there is no need to check for new == old
    1369             :          * because fd_getfile will return NULL if the file at indx is
    1370             :          * newly created by falloc.
    1371             :          */
    1372           0 :         if ((wfp = fd_getfile(fdp, dupfd)) == NULL)
    1373           0 :                 return (EBADF);
    1374             : 
    1375             :         /*
    1376             :          * Check that the mode the file is being opened for is a
    1377             :          * subset of the mode of the existing descriptor.
    1378             :          */
    1379           0 :         if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) {
    1380           0 :                 FRELE(wfp, p);
    1381           0 :                 return (EACCES);
    1382             :         }
    1383           0 :         if (wfp->f_count >= FDUP_MAX_COUNT) {
    1384           0 :                 FRELE(wfp, p);
    1385           0 :                 return (EDEADLK);
    1386             :         }
    1387             : 
    1388           0 :         KASSERT(wfp->f_iflags & FIF_INSERTED);
    1389             : 
    1390           0 :         mtx_enter(&fdp->fd_fplock);
    1391           0 :         KASSERT(fdp->fd_ofiles[indx] == NULL);
    1392           0 :         fdp->fd_ofiles[indx] = wfp;
    1393           0 :         mtx_leave(&fdp->fd_fplock);
    1394             : 
    1395           0 :         fdp->fd_ofileflags[indx] = (fdp->fd_ofileflags[indx] & UF_EXCLOSE) |
    1396           0 :             (fdp->fd_ofileflags[dupfd] & ~UF_EXCLOSE);
    1397             : 
    1398           0 :         return (0);
    1399           0 : }
    1400             : 
    1401             : /*
    1402             :  * Close any files on exec?
    1403             :  */
    1404             : void
    1405           0 : fdcloseexec(struct proc *p)
    1406             : {
    1407           0 :         struct filedesc *fdp = p->p_fd;
    1408             :         int fd;
    1409             : 
    1410           0 :         fdplock(fdp);
    1411           0 :         for (fd = 0; fd <= fdp->fd_lastfile; fd++) {
    1412           0 :                 fdp->fd_ofileflags[fd] &= ~UF_PLEDGED;
    1413           0 :                 if (fdp->fd_ofileflags[fd] & UF_EXCLOSE)
    1414           0 :                         (void) fdrelease(p, fd);
    1415             :         }
    1416           0 :         fdpunlock(fdp);
    1417           0 : }
    1418             : 
    1419             : int
    1420           0 : sys_closefrom(struct proc *p, void *v, register_t *retval)
    1421             : {
    1422           0 :         struct sys_closefrom_args *uap = v;
    1423           0 :         struct filedesc *fdp = p->p_fd;
    1424             :         u_int startfd, i;
    1425             : 
    1426           0 :         startfd = SCARG(uap, fd);
    1427           0 :         fdplock(fdp);
    1428             : 
    1429           0 :         if (startfd > fdp->fd_lastfile) {
    1430           0 :                 fdpunlock(fdp);
    1431           0 :                 return (EBADF);
    1432             :         }
    1433             : 
    1434           0 :         for (i = startfd; i <= fdp->fd_lastfile; i++)
    1435           0 :                 fdrelease(p, i);
    1436             : 
    1437           0 :         fdpunlock(fdp);
    1438           0 :         return (0);
    1439           0 : }
    1440             : 
    1441             : int
    1442           0 : sys_getdtablecount(struct proc *p, void *v, register_t *retval)
    1443             : {
    1444           0 :         *retval = p->p_fd->fd_openfd;
    1445           0 :         return (0);
    1446             : }

Generated by: LCOV version 1.13