123367Smckusick /* 247653Skarels * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. 337728Smckusick * All rights reserved. 423367Smckusick * 544431Sbostic * %sccs.include.redist.c% 637728Smckusick * 7*54934Storek * @(#)kern_descrip.c 7.37 (Berkeley) 07/10/92 823367Smckusick */ 97422Sroot 1017089Sbloom #include "param.h" 1117089Sbloom #include "systm.h" 1245914Smckusick #include "filedesc.h" 1317089Sbloom #include "kernel.h" 1437728Smckusick #include "vnode.h" 1517089Sbloom #include "proc.h" 1617089Sbloom #include "file.h" 1717089Sbloom #include "socket.h" 1817089Sbloom #include "socketvar.h" 1917089Sbloom #include "stat.h" 2017089Sbloom #include "ioctl.h" 2146200Smckusick #include "fcntl.h" 2245914Smckusick #include "malloc.h" 2345914Smckusick #include "syslog.h" 2447653Skarels #include "resourcevar.h" 257497Sroot 267422Sroot /* 277497Sroot * Descriptor management. 287422Sroot */ 2949981Smckusick struct file *filehead; /* head of list of open files */ 3049981Smckusick int nfiles; /* actual number of open files */ 317497Sroot 327497Sroot /* 337497Sroot * System calls on descriptors. 347497Sroot */ 35*54934Storek struct getdtablesize_args { 36*54934Storek int dummy; 37*54934Storek }; 3842863Smckusick /* ARGSUSED */ 3942863Smckusick getdtablesize(p, uap, retval) 4042863Smckusick struct proc *p; 41*54934Storek struct getdtablesize_args *uap; 4242863Smckusick int *retval; 437497Sroot { 447497Sroot 4547540Skarels *retval = p->p_rlimit[RLIMIT_OFILE].rlim_cur; 4644404Skarels return (0); 477497Sroot } 487497Sroot 4942863Smckusick /* 5042863Smckusick * Duplicate a file descriptor. 5142863Smckusick */ 52*54934Storek struct dup_args { 53*54934Storek int i; 54*54934Storek }; 5542863Smckusick /* ARGSUSED */ 5642863Smckusick dup(p, uap, retval) 5742863Smckusick struct proc *p; 58*54934Storek struct dup_args *uap; 5942863Smckusick int *retval; 607422Sroot { 6145914Smckusick register struct filedesc *fdp = p->p_fd; 627696Ssam struct file *fp; 6342863Smckusick int fd, error; 647497Sroot 6542863Smckusick /* 6642863Smckusick * XXX Compatibility 6742863Smckusick */ 6844404Skarels if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); } 697497Sroot 7047540Skarels if ((unsigned)uap->i >= fdp->fd_nfiles || 7147653Skarels (fp = fdp->fd_ofiles[uap->i]) == NULL) 7244404Skarels return (EBADF); 7347540Skarels if (error = fdalloc(p, 0, &fd)) 7444404Skarels return (error); 7547653Skarels fdp->fd_ofiles[fd] = fp; 7647653Skarels fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE; 7742863Smckusick fp->f_count++; 7845914Smckusick if (fd > fdp->fd_lastfile) 7945914Smckusick fdp->fd_lastfile = fd; 8042863Smckusick *retval = fd; 8144404Skarels return (0); 827497Sroot } 837497Sroot 8442863Smckusick /* 8542863Smckusick * Duplicate a file descriptor to a particular value. 8642863Smckusick */ 87*54934Storek struct dup2_args { 88*54934Storek u_int from; 89*54934Storek u_int to; 90*54934Storek }; 9142863Smckusick /* ARGSUSED */ 9242863Smckusick dup2(p, uap, retval) 9342863Smckusick struct proc *p; 94*54934Storek struct dup2_args *uap; 9542863Smckusick int *retval; 967497Sroot { 9745914Smckusick register struct filedesc *fdp = p->p_fd; 987497Sroot register struct file *fp; 9947653Skarels register u_int old = uap->from, new = uap->to; 10045914Smckusick int i, error; 1017422Sroot 10247653Skarels if (old >= fdp->fd_nfiles || 10347653Skarels (fp = fdp->fd_ofiles[old]) == NULL || 10447653Skarels new >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) 10544404Skarels return (EBADF); 10647653Skarels *retval = new; 10747653Skarels if (old == new) 10844404Skarels return (0); 10947653Skarels if (new >= fdp->fd_nfiles) { 11047653Skarels if (error = fdalloc(p, new, &i)) 11145914Smckusick return (error); 11247653Skarels if (new != i) 11347540Skarels panic("dup2: fdalloc"); 11447653Skarels } else if (fdp->fd_ofiles[new]) { 11547653Skarels if (fdp->fd_ofileflags[new] & UF_MAPPED) 11647653Skarels (void) munmapfd(p, new); 11747653Skarels /* 11847653Skarels * dup2() must succeed even if the close has an error. 11947653Skarels */ 12047653Skarels (void) closef(fdp->fd_ofiles[new], p); 1217422Sroot } 12247653Skarels fdp->fd_ofiles[new] = fp; 12347653Skarels fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; 12442863Smckusick fp->f_count++; 12547653Skarels if (new > fdp->fd_lastfile) 12647653Skarels fdp->fd_lastfile = new; 12747653Skarels return (0); 1287696Ssam } 1297696Ssam 13012748Ssam /* 13112748Ssam * The file control system call. 13212748Ssam */ 133*54934Storek struct fcntl_args { 134*54934Storek int fd; 135*54934Storek int cmd; 136*54934Storek int arg; 137*54934Storek }; 13842863Smckusick /* ARGSUSED */ 13942863Smckusick fcntl(p, uap, retval) 14042863Smckusick struct proc *p; 141*54934Storek register struct fcntl_args *uap; 14242863Smckusick int *retval; 14342863Smckusick { 14445914Smckusick register struct filedesc *fdp = p->p_fd; 14542863Smckusick register struct file *fp; 14612748Ssam register char *pop; 14746200Smckusick struct vnode *vp; 14848029Smckusick int i, tmp, error, flg = F_POSIX; 14946200Smckusick struct flock fl; 1507497Sroot 15147540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 15247653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 15344404Skarels return (EBADF); 15447653Skarels pop = &fdp->fd_ofileflags[uap->fd]; 15512748Ssam switch(uap->cmd) { 15615076Skarels case F_DUPFD: 15747540Skarels if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) 15844404Skarels return (EINVAL); 15947540Skarels if (error = fdalloc(p, uap->arg, &i)) 16044404Skarels return (error); 16147653Skarels fdp->fd_ofiles[i] = fp; 16247653Skarels fdp->fd_ofileflags[i] = *pop &~ UF_EXCLOSE; 16342863Smckusick fp->f_count++; 16445914Smckusick if (i > fdp->fd_lastfile) 16545914Smckusick fdp->fd_lastfile = i; 16642863Smckusick *retval = i; 16744404Skarels return (0); 1687497Sroot 16915076Skarels case F_GETFD: 17042863Smckusick *retval = *pop & 1; 17144404Skarels return (0); 1727422Sroot 17315076Skarels case F_SETFD: 17412748Ssam *pop = (*pop &~ 1) | (uap->arg & 1); 17544404Skarels return (0); 1768145Sroot 17715076Skarels case F_GETFL: 17846495Skarels *retval = OFLAGS(fp->f_flag); 17944404Skarels return (0); 1808145Sroot 18115076Skarels case F_SETFL: 18246495Skarels fp->f_flag &= ~FCNTLFLAGS; 18346495Skarels fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS; 18449940Smckusick tmp = fp->f_flag & FNONBLOCK; 18548029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 18648029Smckusick if (error) 18744404Skarels return (error); 18849940Smckusick tmp = fp->f_flag & FASYNC; 18948029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); 19048029Smckusick if (!error) 19148029Smckusick return (0); 19249940Smckusick fp->f_flag &= ~FNONBLOCK; 19348029Smckusick tmp = 0; 19448029Smckusick (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 19544404Skarels return (error); 1967422Sroot 19715076Skarels case F_GETOWN: 19848029Smckusick if (fp->f_type == DTYPE_SOCKET) { 19948029Smckusick *retval = ((struct socket *)fp->f_data)->so_pgid; 20048029Smckusick return (0); 20148029Smckusick } 20248029Smckusick error = (*fp->f_ops->fo_ioctl) 20348029Smckusick (fp, (int)TIOCGPGRP, (caddr_t)retval, p); 20448029Smckusick *retval = -*retval; 20548029Smckusick return (error); 2067422Sroot 20715076Skarels case F_SETOWN: 20848029Smckusick if (fp->f_type == DTYPE_SOCKET) { 20948029Smckusick ((struct socket *)fp->f_data)->so_pgid = uap->arg; 21048029Smckusick return (0); 21148029Smckusick } 21248029Smckusick if (uap->arg <= 0) { 21348029Smckusick uap->arg = -uap->arg; 21448029Smckusick } else { 21548029Smckusick struct proc *p1 = pfind(uap->arg); 21648029Smckusick if (p1 == 0) 21748029Smckusick return (ESRCH); 21848029Smckusick uap->arg = p1->p_pgrp->pg_id; 21948029Smckusick } 22048029Smckusick return ((*fp->f_ops->fo_ioctl) 22148029Smckusick (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p)); 2228115Sroot 22346200Smckusick case F_SETLKW: 22448029Smckusick flg |= F_WAIT; 22546200Smckusick /* Fall into F_SETLK */ 22646200Smckusick 22746200Smckusick case F_SETLK: 22846200Smckusick if (fp->f_type != DTYPE_VNODE) 22946200Smckusick return (EBADF); 23046200Smckusick vp = (struct vnode *)fp->f_data; 23146200Smckusick /* Copy in the lock structure */ 23246200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 23346200Smckusick if (error) 23446200Smckusick return (error); 23546200Smckusick if (fl.l_whence == SEEK_CUR) 23646200Smckusick fl.l_start += fp->f_offset; 23746200Smckusick switch (fl.l_type) { 23846200Smckusick 23946200Smckusick case F_RDLCK: 24046200Smckusick if ((fp->f_flag & FREAD) == 0) 24146200Smckusick return (EBADF); 24249951Smckusick p->p_flag |= SADVLCK; 24348029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 24446200Smckusick 24546200Smckusick case F_WRLCK: 24646200Smckusick if ((fp->f_flag & FWRITE) == 0) 24746200Smckusick return (EBADF); 24849951Smckusick p->p_flag |= SADVLCK; 24948029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 25046200Smckusick 25146200Smckusick case F_UNLCK: 25248029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl, 25348029Smckusick F_POSIX)); 25446200Smckusick 25546200Smckusick default: 25646200Smckusick return (EINVAL); 25746200Smckusick } 25846200Smckusick 25946200Smckusick case F_GETLK: 26046200Smckusick if (fp->f_type != DTYPE_VNODE) 26146200Smckusick return (EBADF); 26246200Smckusick vp = (struct vnode *)fp->f_data; 26346200Smckusick /* Copy in the lock structure */ 26446200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 26546200Smckusick if (error) 26646200Smckusick return (error); 26746765Smckusick if (fl.l_whence == SEEK_CUR) 26846765Smckusick fl.l_start += fp->f_offset; 26948029Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX)) 27046200Smckusick return (error); 27146200Smckusick return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl))); 27246200Smckusick 27312748Ssam default: 27444404Skarels return (EINVAL); 2757422Sroot } 27642863Smckusick /* NOTREACHED */ 2777422Sroot } 2787422Sroot 27942863Smckusick /* 28042863Smckusick * Close a file descriptor. 28142863Smckusick */ 282*54934Storek struct close_args { 283*54934Storek int fd; 284*54934Storek }; 28542863Smckusick /* ARGSUSED */ 28642863Smckusick close(p, uap, retval) 28742863Smckusick struct proc *p; 288*54934Storek struct close_args *uap; 28942863Smckusick int *retval; 2908029Sroot { 29145914Smckusick register struct filedesc *fdp = p->p_fd; 29212748Ssam register struct file *fp; 29347540Skarels register int fd = uap->fd; 29413044Ssam register u_char *pf; 2958029Sroot 29647540Skarels if ((unsigned)fd >= fdp->fd_nfiles || 29747653Skarels (fp = fdp->fd_ofiles[fd]) == NULL) 29844404Skarels return (EBADF); 29947653Skarels pf = (u_char *)&fdp->fd_ofileflags[fd]; 30013044Ssam if (*pf & UF_MAPPED) 30147540Skarels (void) munmapfd(p, fd); 30247653Skarels fdp->fd_ofiles[fd] = NULL; 30347653Skarels while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 30445914Smckusick fdp->fd_lastfile--; 30547540Skarels if (fd < fdp->fd_freefile) 30647540Skarels fdp->fd_freefile = fd; 30715550Skarels *pf = 0; 30847540Skarels return (closef(fp, p)); 3098029Sroot } 3108029Sroot 31154346Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 31242863Smckusick /* 31342863Smckusick * Return status information about a file descriptor. 31442863Smckusick */ 315*54934Storek struct ofstat_args { 316*54934Storek int fd; 317*54934Storek struct ostat *sb; 318*54934Storek }; 31942863Smckusick /* ARGSUSED */ 32053758Smckusick ofstat(p, uap, retval) 32142863Smckusick struct proc *p; 322*54934Storek register struct ofstat_args *uap; 32353466Smckusick int *retval; 32453466Smckusick { 32553466Smckusick register struct filedesc *fdp = p->p_fd; 32653466Smckusick register struct file *fp; 32753466Smckusick struct stat ub; 32853466Smckusick struct ostat oub; 32953466Smckusick int error; 33053466Smckusick 33153466Smckusick if ((unsigned)uap->fd >= fdp->fd_nfiles || 33253466Smckusick (fp = fdp->fd_ofiles[uap->fd]) == NULL) 33353466Smckusick return (EBADF); 33453466Smckusick switch (fp->f_type) { 33553466Smckusick 33653466Smckusick case DTYPE_VNODE: 33753466Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p); 33853466Smckusick break; 33953466Smckusick 34053466Smckusick case DTYPE_SOCKET: 34153466Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 34253466Smckusick break; 34353466Smckusick 34453466Smckusick default: 34554346Smckusick panic("ofstat"); 34653466Smckusick /*NOTREACHED*/ 34753466Smckusick } 34853466Smckusick cvtstat(&ub, &oub); 34953466Smckusick if (error == 0) 35053466Smckusick error = copyout((caddr_t)&oub, (caddr_t)uap->sb, sizeof (oub)); 35153466Smckusick return (error); 35253466Smckusick } 35354346Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 35453466Smckusick 35553466Smckusick /* 35653466Smckusick * Return status information about a file descriptor. 35753466Smckusick */ 358*54934Storek struct fstat_args { 359*54934Storek int fd; 360*54934Storek struct stat *sb; 361*54934Storek }; 36253466Smckusick /* ARGSUSED */ 36353758Smckusick fstat(p, uap, retval) 36453466Smckusick struct proc *p; 365*54934Storek register struct fstat_args *uap; 36642863Smckusick int *retval; 36713044Ssam { 36845914Smckusick register struct filedesc *fdp = p->p_fd; 36913044Ssam register struct file *fp; 37013044Ssam struct stat ub; 37142863Smckusick int error; 37213044Ssam 37347540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 37447653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 37544404Skarels return (EBADF); 37613044Ssam switch (fp->f_type) { 37713044Ssam 37837728Smckusick case DTYPE_VNODE: 37948029Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p); 38013044Ssam break; 38113044Ssam 38213044Ssam case DTYPE_SOCKET: 38342863Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 38413044Ssam break; 38513044Ssam 38613044Ssam default: 38713044Ssam panic("fstat"); 38813044Ssam /*NOTREACHED*/ 38913044Ssam } 39042863Smckusick if (error == 0) 39142863Smckusick error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); 39244404Skarels return (error); 39313044Ssam } 39413044Ssam 3957422Sroot /* 39647540Skarels * Allocate a file descriptor for the process. 3977422Sroot */ 39847540Skarels int fdexpand; 39945914Smckusick 40047540Skarels fdalloc(p, want, result) 40147540Skarels struct proc *p; 40247540Skarels int want; 40337728Smckusick int *result; 4047422Sroot { 40547540Skarels register struct filedesc *fdp = p->p_fd; 40647540Skarels register int i; 40747540Skarels int lim, last, nfiles; 40845914Smckusick struct file **newofile; 40945914Smckusick char *newofileflags; 4107497Sroot 41147540Skarels /* 41247540Skarels * Search for a free descriptor starting at the higher 41347540Skarels * of want or fd_freefile. If that fails, consider 41447540Skarels * expanding the ofile array. 41547540Skarels */ 41647540Skarels lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur; 41745914Smckusick for (;;) { 41847540Skarels last = min(fdp->fd_nfiles, lim); 41947540Skarels if ((i = want) < fdp->fd_freefile) 42047540Skarels i = fdp->fd_freefile; 42147540Skarels for (; i < last; i++) { 42247653Skarels if (fdp->fd_ofiles[i] == NULL) { 42347653Skarels fdp->fd_ofileflags[i] = 0; 42447540Skarels if (i > fdp->fd_lastfile) 42547540Skarels fdp->fd_lastfile = i; 42647653Skarels if (want <= fdp->fd_freefile) 42747540Skarels fdp->fd_freefile = i; 42847540Skarels *result = i; 42945914Smckusick return (0); 43045914Smckusick } 4317497Sroot } 43247540Skarels 43347540Skarels /* 43447540Skarels * No space in current array. Expand? 43547540Skarels */ 43647540Skarels if (fdp->fd_nfiles >= lim) 43745914Smckusick return (EMFILE); 43847653Skarels if (fdp->fd_nfiles < NDEXTENT) 43947653Skarels nfiles = NDEXTENT; 44047653Skarels else 44147653Skarels nfiles = 2 * fdp->fd_nfiles; 44247540Skarels MALLOC(newofile, struct file **, nfiles * OFILESIZE, 44347540Skarels M_FILEDESC, M_WAITOK); 44447540Skarels newofileflags = (char *) &newofile[nfiles]; 44547540Skarels /* 44647540Skarels * Copy the existing ofile and ofileflags arrays 44747540Skarels * and zero the new portion of each array. 44847540Skarels */ 44947540Skarels bcopy(fdp->fd_ofiles, newofile, 45047540Skarels (i = sizeof(struct file *) * fdp->fd_nfiles)); 45147540Skarels bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i); 45247540Skarels bcopy(fdp->fd_ofileflags, newofileflags, 45347540Skarels (i = sizeof(char) * fdp->fd_nfiles)); 45447540Skarels bzero(newofileflags + i, nfiles * sizeof(char) - i); 45547653Skarels if (fdp->fd_nfiles > NDFILE) 45647653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 45747540Skarels fdp->fd_ofiles = newofile; 45847540Skarels fdp->fd_ofileflags = newofileflags; 45947540Skarels fdp->fd_nfiles = nfiles; 46047540Skarels fdexpand++; 46139733Smckusick } 4627497Sroot } 4637497Sroot 46442863Smckusick /* 46547653Skarels * Check to see whether n user file descriptors 46647653Skarels * are available to the process p. 46742863Smckusick */ 46847540Skarels fdavail(p, n) 46947540Skarels struct proc *p; 47047540Skarels register int n; 47112748Ssam { 47247540Skarels register struct filedesc *fdp = p->p_fd; 47347653Skarels register struct file **fpp; 47447540Skarels register int i; 47512748Ssam 47647540Skarels if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 && 47747540Skarels (n -= i) <= 0) 47847540Skarels return (1); 47947653Skarels fpp = &fdp->fd_ofiles[fdp->fd_freefile]; 48047653Skarels for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++) 48147653Skarels if (*fpp == NULL && --n <= 0) 48247540Skarels return (1); 48347540Skarels return (0); 48412748Ssam } 48512748Ssam 4867497Sroot /* 48747540Skarels * Create a new open file structure and allocate 48847540Skarels * a file decriptor for the process that refers to it. 4897497Sroot */ 49045914Smckusick falloc(p, resultfp, resultfd) 49145914Smckusick register struct proc *p; 49237728Smckusick struct file **resultfp; 49337728Smckusick int *resultfd; 4947497Sroot { 49549981Smckusick register struct file *fp, *fq, **fpp; 49637728Smckusick int error, i; 4977422Sroot 49847540Skarels if (error = fdalloc(p, 0, &i)) 49937728Smckusick return (error); 50049981Smckusick if (nfiles >= maxfiles) { 50149981Smckusick tablefull("file"); 50249981Smckusick return (ENFILE); 50349981Smckusick } 50449981Smckusick /* 50549981Smckusick * Allocate a new file descriptor. 50649981Smckusick * If the process has file descriptor zero open, add to the list 50749981Smckusick * of open files at that point, otherwise put it at the front of 50849981Smckusick * the list of open files. 50949981Smckusick */ 51049981Smckusick nfiles++; 51149981Smckusick MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK); 51249981Smckusick if (fq = p->p_fd->fd_ofiles[0]) 51349981Smckusick fpp = &fq->f_filef; 51449981Smckusick else 51549981Smckusick fpp = &filehead; 51650129Smckusick p->p_fd->fd_ofiles[i] = fp; 51749981Smckusick if (fq = *fpp) 51849981Smckusick fq->f_fileb = &fp->f_filef; 51949981Smckusick fp->f_filef = fq; 52049981Smckusick fp->f_fileb = fpp; 52149981Smckusick *fpp = fp; 52212748Ssam fp->f_count = 1; 52349981Smckusick fp->f_msgcount = 0; 5247497Sroot fp->f_offset = 0; 52547540Skarels fp->f_cred = p->p_ucred; 52637728Smckusick crhold(fp->f_cred); 52737728Smckusick if (resultfp) 52837728Smckusick *resultfp = fp; 52937728Smckusick if (resultfd) 53037728Smckusick *resultfd = i; 53137728Smckusick return (0); 5327497Sroot } 53312748Ssam 5347497Sroot /* 53549981Smckusick * Free a file descriptor. 53649981Smckusick */ 53749981Smckusick ffree(fp) 53849981Smckusick register struct file *fp; 53949981Smckusick { 54049981Smckusick register struct file *fq; 54149981Smckusick 54249981Smckusick if (fq = fp->f_filef) 54349981Smckusick fq->f_fileb = fp->f_fileb; 54449981Smckusick *fp->f_fileb = fq; 54549981Smckusick crfree(fp->f_cred); 54649981Smckusick #ifdef DIAGNOSTIC 54749981Smckusick fp->f_filef = NULL; 54849981Smckusick fp->f_fileb = NULL; 54949981Smckusick fp->f_count = 0; 55049981Smckusick #endif 55149981Smckusick nfiles--; 55249981Smckusick FREE(fp, M_FILE); 55349981Smckusick } 55449981Smckusick 55549981Smckusick /* 55647540Skarels * Copy a filedesc structure. 55745914Smckusick */ 55845914Smckusick struct filedesc * 55947540Skarels fdcopy(p) 56047540Skarels struct proc *p; 56145914Smckusick { 56247653Skarels register struct filedesc *newfdp, *fdp = p->p_fd; 56347653Skarels register struct file **fpp; 56445914Smckusick register int i; 56545914Smckusick 56647653Skarels MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0), 56747653Skarels M_FILEDESC, M_WAITOK); 56847653Skarels bcopy(fdp, newfdp, sizeof(struct filedesc)); 56945914Smckusick VREF(newfdp->fd_cdir); 57045914Smckusick if (newfdp->fd_rdir) 57145914Smckusick VREF(newfdp->fd_rdir); 57245914Smckusick newfdp->fd_refcnt = 1; 57347540Skarels 57447540Skarels /* 57547653Skarels * If the number of open files fits in the internal arrays 57647653Skarels * of the open file structure, use them, otherwise allocate 57747653Skarels * additional memory for the number of descriptors currently 57847653Skarels * in use. 57947540Skarels */ 58047653Skarels if (newfdp->fd_lastfile < NDFILE) { 58147653Skarels newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles; 58247653Skarels newfdp->fd_ofileflags = 58347653Skarels ((struct filedesc0 *) newfdp)->fd_dfileflags; 58447653Skarels i = NDFILE; 58547653Skarels } else { 58647653Skarels /* 58747653Skarels * Compute the smallest multiple of NDEXTENT needed 58847653Skarels * for the file descriptors currently in use, 58947653Skarels * allowing the table to shrink. 59047653Skarels */ 59147653Skarels i = newfdp->fd_nfiles; 59247653Skarels while (i > 2 * NDEXTENT && i >= newfdp->fd_lastfile * 2) 59347653Skarels i /= 2; 59447653Skarels MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE, 59547653Skarels M_FILEDESC, M_WAITOK); 59647653Skarels newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; 59747653Skarels } 59847540Skarels newfdp->fd_nfiles = i; 59947540Skarels bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **)); 60047540Skarels bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char)); 60147653Skarels fpp = newfdp->fd_ofiles; 60247653Skarels for (i = newfdp->fd_lastfile; i-- >= 0; fpp++) 60347653Skarels if (*fpp != NULL) 60447653Skarels (*fpp)->f_count++; 60545914Smckusick return (newfdp); 60645914Smckusick } 60745914Smckusick 60845914Smckusick /* 60945914Smckusick * Release a filedesc structure. 61045914Smckusick */ 61147653Skarels void 61247540Skarels fdfree(p) 61347540Skarels struct proc *p; 61445914Smckusick { 61547540Skarels register struct filedesc *fdp = p->p_fd; 61647653Skarels struct file **fpp; 61745914Smckusick register int i; 61845914Smckusick 61947540Skarels if (--fdp->fd_refcnt > 0) 62045914Smckusick return; 62147653Skarels fpp = fdp->fd_ofiles; 62247653Skarels for (i = fdp->fd_lastfile; i-- >= 0; fpp++) 62347653Skarels if (*fpp) 62447653Skarels (void) closef(*fpp, p); 62547653Skarels if (fdp->fd_nfiles > NDFILE) 62647653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 62745914Smckusick vrele(fdp->fd_cdir); 62845914Smckusick if (fdp->fd_rdir) 62945914Smckusick vrele(fdp->fd_rdir); 63047540Skarels FREE(fdp, M_FILEDESC); 63145914Smckusick } 63245914Smckusick 63345914Smckusick /* 6347497Sroot * Internal form of close. 63512748Ssam * Decrement reference count on file structure. 63652034Skarels * Note: p may be NULL when closing a file 63752034Skarels * that was being passed in a message. 6387497Sroot */ 63947540Skarels closef(fp, p) 6407497Sroot register struct file *fp; 64149981Smckusick register struct proc *p; 6427497Sroot { 64346200Smckusick struct vnode *vp; 64446200Smckusick struct flock lf; 64539354Smckusick int error; 6467497Sroot 6477422Sroot if (fp == NULL) 64839354Smckusick return (0); 64946200Smckusick /* 65046200Smckusick * POSIX record locking dictates that any close releases ALL 65146200Smckusick * locks owned by this process. This is handled by setting 65246200Smckusick * a flag in the unlock to free ONLY locks obeying POSIX 65346200Smckusick * semantics, and not to free BSD-style file locks. 65452034Skarels * If the descriptor was in a message, POSIX-style locks 65552034Skarels * aren't passed with the descriptor. 65646200Smckusick */ 65752034Skarels if (p && (p->p_flag & SADVLCK) && fp->f_type == DTYPE_VNODE) { 65846200Smckusick lf.l_whence = SEEK_SET; 65946200Smckusick lf.l_start = 0; 66046200Smckusick lf.l_len = 0; 66146200Smckusick lf.l_type = F_UNLCK; 66246200Smckusick vp = (struct vnode *)fp->f_data; 66348029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX); 66446200Smckusick } 66547540Skarels if (--fp->f_count > 0) 66639354Smckusick return (0); 66747540Skarels if (fp->f_count < 0) 66847540Skarels panic("closef: count < 0"); 66949951Smckusick if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) { 67049951Smckusick lf.l_whence = SEEK_SET; 67149951Smckusick lf.l_start = 0; 67249951Smckusick lf.l_len = 0; 67349951Smckusick lf.l_type = F_UNLCK; 67449951Smckusick vp = (struct vnode *)fp->f_data; 67548029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); 67649951Smckusick } 67748029Smckusick error = (*fp->f_ops->fo_close)(fp, p); 67849981Smckusick ffree(fp); 67939354Smckusick return (error); 6807422Sroot } 68113044Ssam 68213044Ssam /* 68313044Ssam * Apply an advisory lock on a file descriptor. 68446200Smckusick * 68546200Smckusick * Just attempt to get a record lock of the requested type on 68646200Smckusick * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). 68713044Ssam */ 688*54934Storek struct flock_args { 689*54934Storek int fd; 690*54934Storek int how; 691*54934Storek }; 69242863Smckusick /* ARGSUSED */ 69342863Smckusick flock(p, uap, retval) 69442863Smckusick struct proc *p; 695*54934Storek register struct flock_args *uap; 69642863Smckusick int *retval; 69742863Smckusick { 69845914Smckusick register struct filedesc *fdp = p->p_fd; 69913044Ssam register struct file *fp; 70046200Smckusick struct vnode *vp; 70146200Smckusick struct flock lf; 70246200Smckusick int error; 70313044Ssam 70447540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 70547653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 70644404Skarels return (EBADF); 70742863Smckusick if (fp->f_type != DTYPE_VNODE) 70844404Skarels return (EOPNOTSUPP); 70946200Smckusick vp = (struct vnode *)fp->f_data; 71046200Smckusick lf.l_whence = SEEK_SET; 71146200Smckusick lf.l_start = 0; 71246200Smckusick lf.l_len = 0; 71313101Ssam if (uap->how & LOCK_UN) { 71446200Smckusick lf.l_type = F_UNLCK; 71549951Smckusick fp->f_flag &= ~FHASLOCK; 71648029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK)); 71713044Ssam } 71817998Skarels if (uap->how & LOCK_EX) 71946200Smckusick lf.l_type = F_WRLCK; 72046200Smckusick else if (uap->how & LOCK_SH) 72146200Smckusick lf.l_type = F_RDLCK; 72246200Smckusick else 72346200Smckusick return (EBADF); 72449951Smckusick fp->f_flag |= FHASLOCK; 72546200Smckusick if (uap->how & LOCK_NB) 72648029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK)); 72748029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); 72813044Ssam } 72937586Smarc 73037586Smarc /* 73137586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 73237586Smarc * 73337586Smarc * Opening minor device N dup()s the file (if any) connected to file 73437586Smarc * descriptor N belonging to the calling process. Note that this driver 73537586Smarc * consists of only the ``open()'' routine, because all subsequent 73637586Smarc * references to this file will be direct to the other driver. 73737586Smarc */ 73837728Smckusick /* ARGSUSED */ 73952568Smckusick fdopen(dev, mode, type, p) 74037586Smarc dev_t dev; 74137728Smckusick int mode, type; 74252568Smckusick struct proc *p; 74337586Smarc { 74437586Smarc 74537586Smarc /* 74647540Skarels * XXX Kludge: set curproc->p_dupfd to contain the value of the 74743406Smckusick * the file descriptor being sought for duplication. The error 74843406Smckusick * return ensures that the vnode for this device will be released 74943406Smckusick * by vn_open. Open will detect this special error and take the 75043406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN 75143406Smckusick * will simply report the error. 75237586Smarc */ 75352568Smckusick p->p_dupfd = minor(dev); 75443406Smckusick return (ENODEV); 75543406Smckusick } 75640873Sbostic 75743406Smckusick /* 75843406Smckusick * Duplicate the specified descriptor to a free descriptor. 75943406Smckusick */ 76053826Spendry dupfdopen(fdp, indx, dfd, mode, error) 76145914Smckusick register struct filedesc *fdp; 76243406Smckusick register int indx, dfd; 76343406Smckusick int mode; 76453826Spendry int error; 76543406Smckusick { 76643406Smckusick register struct file *wfp; 76743406Smckusick struct file *fp; 76843406Smckusick 76937586Smarc /* 77043406Smckusick * If the to-be-dup'd fd number is greater than the allowed number 77143406Smckusick * of file descriptors, or the fd to be dup'd has already been 77243406Smckusick * closed, reject. Note, check for new == old is necessary as 77343406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor 77443406Smckusick * as the new descriptor. 77537586Smarc */ 77647653Skarels fp = fdp->fd_ofiles[indx]; 77747653Skarels if ((u_int)dfd >= fdp->fd_nfiles || 77847653Skarels (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp) 77937586Smarc return (EBADF); 78040873Sbostic 78137586Smarc /* 78253826Spendry * There are two cases of interest here. 78353826Spendry * 78453826Spendry * For ENODEV simply dup (dfd) to file descriptor 78553826Spendry * (indx) and return. 78653826Spendry * 78753826Spendry * For ENXIO steal away the file structure from (dfd) and 78853826Spendry * store it in (indx). (dfd) is effectively closed by 78953826Spendry * this operation. 79053826Spendry * 79153826Spendry * Any other error code is just returned. 79237586Smarc */ 79353826Spendry switch (error) { 79453826Spendry case ENODEV: 79553826Spendry /* 79653826Spendry * Check that the mode the file is being opened for is a 79753826Spendry * subset of the mode of the existing descriptor. 79853826Spendry */ 79953826Spendry if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) 80053826Spendry return (EACCES); 80153826Spendry fdp->fd_ofiles[indx] = wfp; 80253826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 80353826Spendry wfp->f_count++; 80453826Spendry if (indx > fdp->fd_lastfile) 80553826Spendry fdp->fd_lastfile = indx; 80653826Spendry return (0); 80753826Spendry 80853826Spendry case ENXIO: 80953826Spendry /* 81053826Spendry * Steal away the file pointer from dfd, and stuff it into indx. 81153826Spendry */ 81253826Spendry fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd]; 81353826Spendry fdp->fd_ofiles[dfd] = NULL; 81453826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 81553826Spendry fdp->fd_ofileflags[dfd] = 0; 81653826Spendry /* 81753826Spendry * Complete the clean up of the filedesc structure by 81853826Spendry * recomputing the various hints. 81953826Spendry */ 82053826Spendry if (indx > fdp->fd_lastfile) 82153826Spendry fdp->fd_lastfile = indx; 82253826Spendry else 82353826Spendry while (fdp->fd_lastfile > 0 && 82453826Spendry fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 82553826Spendry fdp->fd_lastfile--; 82653826Spendry if (dfd < fdp->fd_freefile) 82753826Spendry fdp->fd_freefile = dfd; 82853826Spendry return (0); 82953826Spendry 83053826Spendry default: 83153826Spendry return (error); 83253826Spendry } 83353826Spendry /* NOTREACHED */ 83437586Smarc } 835