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*54346Smckusick * @(#)kern_descrip.c 7.35 (Berkeley) 06/23/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 */ 3542863Smckusick /* ARGSUSED */ 3642863Smckusick getdtablesize(p, uap, retval) 3742863Smckusick struct proc *p; 3842863Smckusick struct args *uap; 3942863Smckusick int *retval; 407497Sroot { 417497Sroot 4247540Skarels *retval = p->p_rlimit[RLIMIT_OFILE].rlim_cur; 4344404Skarels return (0); 447497Sroot } 457497Sroot 4642863Smckusick /* 4742863Smckusick * Duplicate a file descriptor. 4842863Smckusick */ 4942863Smckusick /* ARGSUSED */ 5042863Smckusick dup(p, uap, retval) 5142863Smckusick struct proc *p; 5242863Smckusick struct args { 5342863Smckusick int i; 5442863Smckusick } *uap; 5542863Smckusick int *retval; 567422Sroot { 5745914Smckusick register struct filedesc *fdp = p->p_fd; 587696Ssam struct file *fp; 5942863Smckusick int fd, error; 607497Sroot 6142863Smckusick /* 6242863Smckusick * XXX Compatibility 6342863Smckusick */ 6444404Skarels if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); } 657497Sroot 6647540Skarels if ((unsigned)uap->i >= fdp->fd_nfiles || 6747653Skarels (fp = fdp->fd_ofiles[uap->i]) == NULL) 6844404Skarels return (EBADF); 6947540Skarels if (error = fdalloc(p, 0, &fd)) 7044404Skarels return (error); 7147653Skarels fdp->fd_ofiles[fd] = fp; 7247653Skarels fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE; 7342863Smckusick fp->f_count++; 7445914Smckusick if (fd > fdp->fd_lastfile) 7545914Smckusick fdp->fd_lastfile = fd; 7642863Smckusick *retval = fd; 7744404Skarels return (0); 787497Sroot } 797497Sroot 8042863Smckusick /* 8142863Smckusick * Duplicate a file descriptor to a particular value. 8242863Smckusick */ 8342863Smckusick /* ARGSUSED */ 8442863Smckusick dup2(p, uap, retval) 8542863Smckusick struct proc *p; 8647653Skarels struct args { 8747653Skarels u_int from; 8847653Skarels u_int to; 8942863Smckusick } *uap; 9042863Smckusick int *retval; 917497Sroot { 9245914Smckusick register struct filedesc *fdp = p->p_fd; 937497Sroot register struct file *fp; 9447653Skarels register u_int old = uap->from, new = uap->to; 9545914Smckusick int i, error; 967422Sroot 9747653Skarels if (old >= fdp->fd_nfiles || 9847653Skarels (fp = fdp->fd_ofiles[old]) == NULL || 9947653Skarels new >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) 10044404Skarels return (EBADF); 10147653Skarels *retval = new; 10247653Skarels if (old == new) 10344404Skarels return (0); 10447653Skarels if (new >= fdp->fd_nfiles) { 10547653Skarels if (error = fdalloc(p, new, &i)) 10645914Smckusick return (error); 10747653Skarels if (new != i) 10847540Skarels panic("dup2: fdalloc"); 10947653Skarels } else if (fdp->fd_ofiles[new]) { 11047653Skarels if (fdp->fd_ofileflags[new] & UF_MAPPED) 11147653Skarels (void) munmapfd(p, new); 11247653Skarels /* 11347653Skarels * dup2() must succeed even if the close has an error. 11447653Skarels */ 11547653Skarels (void) closef(fdp->fd_ofiles[new], p); 1167422Sroot } 11747653Skarels fdp->fd_ofiles[new] = fp; 11847653Skarels fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; 11942863Smckusick fp->f_count++; 12047653Skarels if (new > fdp->fd_lastfile) 12147653Skarels fdp->fd_lastfile = new; 12247653Skarels return (0); 1237696Ssam } 1247696Ssam 12512748Ssam /* 12612748Ssam * The file control system call. 12712748Ssam */ 12842863Smckusick /* ARGSUSED */ 12942863Smckusick fcntl(p, uap, retval) 13042863Smckusick struct proc *p; 13142863Smckusick register struct args { 13247540Skarels int fd; 13312748Ssam int cmd; 13412748Ssam int arg; 13542863Smckusick } *uap; 13642863Smckusick int *retval; 13742863Smckusick { 13853538Sheideman USES_VOP_ADVLOCK; 13945914Smckusick register struct filedesc *fdp = p->p_fd; 14042863Smckusick register struct file *fp; 14112748Ssam register char *pop; 14246200Smckusick struct vnode *vp; 14348029Smckusick int i, tmp, error, flg = F_POSIX; 14446200Smckusick struct flock fl; 1457497Sroot 14647540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 14747653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 14844404Skarels return (EBADF); 14947653Skarels pop = &fdp->fd_ofileflags[uap->fd]; 15012748Ssam switch(uap->cmd) { 15115076Skarels case F_DUPFD: 15247540Skarels if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) 15344404Skarels return (EINVAL); 15447540Skarels if (error = fdalloc(p, uap->arg, &i)) 15544404Skarels return (error); 15647653Skarels fdp->fd_ofiles[i] = fp; 15747653Skarels fdp->fd_ofileflags[i] = *pop &~ UF_EXCLOSE; 15842863Smckusick fp->f_count++; 15945914Smckusick if (i > fdp->fd_lastfile) 16045914Smckusick fdp->fd_lastfile = i; 16142863Smckusick *retval = i; 16244404Skarels return (0); 1637497Sroot 16415076Skarels case F_GETFD: 16542863Smckusick *retval = *pop & 1; 16644404Skarels return (0); 1677422Sroot 16815076Skarels case F_SETFD: 16912748Ssam *pop = (*pop &~ 1) | (uap->arg & 1); 17044404Skarels return (0); 1718145Sroot 17215076Skarels case F_GETFL: 17346495Skarels *retval = OFLAGS(fp->f_flag); 17444404Skarels return (0); 1758145Sroot 17615076Skarels case F_SETFL: 17746495Skarels fp->f_flag &= ~FCNTLFLAGS; 17846495Skarels fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS; 17949940Smckusick tmp = fp->f_flag & FNONBLOCK; 18048029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 18148029Smckusick if (error) 18244404Skarels return (error); 18349940Smckusick tmp = fp->f_flag & FASYNC; 18448029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); 18548029Smckusick if (!error) 18648029Smckusick return (0); 18749940Smckusick fp->f_flag &= ~FNONBLOCK; 18848029Smckusick tmp = 0; 18948029Smckusick (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 19044404Skarels return (error); 1917422Sroot 19215076Skarels case F_GETOWN: 19348029Smckusick if (fp->f_type == DTYPE_SOCKET) { 19448029Smckusick *retval = ((struct socket *)fp->f_data)->so_pgid; 19548029Smckusick return (0); 19648029Smckusick } 19748029Smckusick error = (*fp->f_ops->fo_ioctl) 19848029Smckusick (fp, (int)TIOCGPGRP, (caddr_t)retval, p); 19948029Smckusick *retval = -*retval; 20048029Smckusick return (error); 2017422Sroot 20215076Skarels case F_SETOWN: 20348029Smckusick if (fp->f_type == DTYPE_SOCKET) { 20448029Smckusick ((struct socket *)fp->f_data)->so_pgid = uap->arg; 20548029Smckusick return (0); 20648029Smckusick } 20748029Smckusick if (uap->arg <= 0) { 20848029Smckusick uap->arg = -uap->arg; 20948029Smckusick } else { 21048029Smckusick struct proc *p1 = pfind(uap->arg); 21148029Smckusick if (p1 == 0) 21248029Smckusick return (ESRCH); 21348029Smckusick uap->arg = p1->p_pgrp->pg_id; 21448029Smckusick } 21548029Smckusick return ((*fp->f_ops->fo_ioctl) 21648029Smckusick (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p)); 2178115Sroot 21846200Smckusick case F_SETLKW: 21948029Smckusick flg |= F_WAIT; 22046200Smckusick /* Fall into F_SETLK */ 22146200Smckusick 22246200Smckusick case F_SETLK: 22346200Smckusick if (fp->f_type != DTYPE_VNODE) 22446200Smckusick return (EBADF); 22546200Smckusick vp = (struct vnode *)fp->f_data; 22646200Smckusick /* Copy in the lock structure */ 22746200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 22846200Smckusick if (error) 22946200Smckusick return (error); 23046200Smckusick if (fl.l_whence == SEEK_CUR) 23146200Smckusick fl.l_start += fp->f_offset; 23246200Smckusick switch (fl.l_type) { 23346200Smckusick 23446200Smckusick case F_RDLCK: 23546200Smckusick if ((fp->f_flag & FREAD) == 0) 23646200Smckusick return (EBADF); 23749951Smckusick p->p_flag |= SADVLCK; 23848029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 23946200Smckusick 24046200Smckusick case F_WRLCK: 24146200Smckusick if ((fp->f_flag & FWRITE) == 0) 24246200Smckusick return (EBADF); 24349951Smckusick p->p_flag |= SADVLCK; 24448029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 24546200Smckusick 24646200Smckusick case F_UNLCK: 24748029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl, 24848029Smckusick F_POSIX)); 24946200Smckusick 25046200Smckusick default: 25146200Smckusick return (EINVAL); 25246200Smckusick } 25346200Smckusick 25446200Smckusick case F_GETLK: 25546200Smckusick if (fp->f_type != DTYPE_VNODE) 25646200Smckusick return (EBADF); 25746200Smckusick vp = (struct vnode *)fp->f_data; 25846200Smckusick /* Copy in the lock structure */ 25946200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 26046200Smckusick if (error) 26146200Smckusick return (error); 26246765Smckusick if (fl.l_whence == SEEK_CUR) 26346765Smckusick fl.l_start += fp->f_offset; 26448029Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX)) 26546200Smckusick return (error); 26646200Smckusick return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl))); 26746200Smckusick 26812748Ssam default: 26944404Skarels return (EINVAL); 2707422Sroot } 27142863Smckusick /* NOTREACHED */ 2727422Sroot } 2737422Sroot 27442863Smckusick /* 27542863Smckusick * Close a file descriptor. 27642863Smckusick */ 27742863Smckusick /* ARGSUSED */ 27842863Smckusick close(p, uap, retval) 27942863Smckusick struct proc *p; 28042863Smckusick struct args { 28147540Skarels int fd; 28242863Smckusick } *uap; 28342863Smckusick int *retval; 2848029Sroot { 28545914Smckusick register struct filedesc *fdp = p->p_fd; 28612748Ssam register struct file *fp; 28747540Skarels register int fd = uap->fd; 28813044Ssam register u_char *pf; 2898029Sroot 29047540Skarels if ((unsigned)fd >= fdp->fd_nfiles || 29147653Skarels (fp = fdp->fd_ofiles[fd]) == NULL) 29244404Skarels return (EBADF); 29347653Skarels pf = (u_char *)&fdp->fd_ofileflags[fd]; 29413044Ssam if (*pf & UF_MAPPED) 29547540Skarels (void) munmapfd(p, fd); 29647653Skarels fdp->fd_ofiles[fd] = NULL; 29747653Skarels while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 29845914Smckusick fdp->fd_lastfile--; 29947540Skarels if (fd < fdp->fd_freefile) 30047540Skarels fdp->fd_freefile = fd; 30115550Skarels *pf = 0; 30247540Skarels return (closef(fp, p)); 3038029Sroot } 3048029Sroot 305*54346Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 30642863Smckusick /* 30742863Smckusick * Return status information about a file descriptor. 30842863Smckusick */ 30942863Smckusick /* ARGSUSED */ 31053758Smckusick ofstat(p, uap, retval) 31142863Smckusick struct proc *p; 31242863Smckusick register struct args { 31347540Skarels int fd; 31453466Smckusick struct ostat *sb; 31553466Smckusick } *uap; 31653466Smckusick int *retval; 31753466Smckusick { 31853466Smckusick register struct filedesc *fdp = p->p_fd; 31953466Smckusick register struct file *fp; 32053466Smckusick struct stat ub; 32153466Smckusick struct ostat oub; 32253466Smckusick int error; 32353466Smckusick 32453466Smckusick if ((unsigned)uap->fd >= fdp->fd_nfiles || 32553466Smckusick (fp = fdp->fd_ofiles[uap->fd]) == NULL) 32653466Smckusick return (EBADF); 32753466Smckusick switch (fp->f_type) { 32853466Smckusick 32953466Smckusick case DTYPE_VNODE: 33053466Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p); 33153466Smckusick break; 33253466Smckusick 33353466Smckusick case DTYPE_SOCKET: 33453466Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 33553466Smckusick break; 33653466Smckusick 33753466Smckusick default: 338*54346Smckusick panic("ofstat"); 33953466Smckusick /*NOTREACHED*/ 34053466Smckusick } 34153466Smckusick cvtstat(&ub, &oub); 34253466Smckusick if (error == 0) 34353466Smckusick error = copyout((caddr_t)&oub, (caddr_t)uap->sb, sizeof (oub)); 34453466Smckusick return (error); 34553466Smckusick } 346*54346Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 34753466Smckusick 34853466Smckusick /* 34953466Smckusick * Return status information about a file descriptor. 35053466Smckusick */ 35153466Smckusick /* ARGSUSED */ 35253758Smckusick fstat(p, uap, retval) 35353466Smckusick struct proc *p; 35453466Smckusick register struct args { 35553466Smckusick int fd; 35642863Smckusick struct stat *sb; 35742863Smckusick } *uap; 35842863Smckusick int *retval; 35913044Ssam { 36045914Smckusick register struct filedesc *fdp = p->p_fd; 36113044Ssam register struct file *fp; 36213044Ssam struct stat ub; 36342863Smckusick int error; 36413044Ssam 36547540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 36647653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 36744404Skarels return (EBADF); 36813044Ssam switch (fp->f_type) { 36913044Ssam 37037728Smckusick case DTYPE_VNODE: 37148029Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p); 37213044Ssam break; 37313044Ssam 37413044Ssam case DTYPE_SOCKET: 37542863Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 37613044Ssam break; 37713044Ssam 37813044Ssam default: 37913044Ssam panic("fstat"); 38013044Ssam /*NOTREACHED*/ 38113044Ssam } 38242863Smckusick if (error == 0) 38342863Smckusick error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); 38444404Skarels return (error); 38513044Ssam } 38613044Ssam 3877422Sroot /* 38847540Skarels * Allocate a file descriptor for the process. 3897422Sroot */ 39047540Skarels int fdexpand; 39145914Smckusick 39247540Skarels fdalloc(p, want, result) 39347540Skarels struct proc *p; 39447540Skarels int want; 39537728Smckusick int *result; 3967422Sroot { 39747540Skarels register struct filedesc *fdp = p->p_fd; 39847540Skarels register int i; 39947540Skarels int lim, last, nfiles; 40045914Smckusick struct file **newofile; 40145914Smckusick char *newofileflags; 4027497Sroot 40347540Skarels /* 40447540Skarels * Search for a free descriptor starting at the higher 40547540Skarels * of want or fd_freefile. If that fails, consider 40647540Skarels * expanding the ofile array. 40747540Skarels */ 40847540Skarels lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur; 40945914Smckusick for (;;) { 41047540Skarels last = min(fdp->fd_nfiles, lim); 41147540Skarels if ((i = want) < fdp->fd_freefile) 41247540Skarels i = fdp->fd_freefile; 41347540Skarels for (; i < last; i++) { 41447653Skarels if (fdp->fd_ofiles[i] == NULL) { 41547653Skarels fdp->fd_ofileflags[i] = 0; 41647540Skarels if (i > fdp->fd_lastfile) 41747540Skarels fdp->fd_lastfile = i; 41847653Skarels if (want <= fdp->fd_freefile) 41947540Skarels fdp->fd_freefile = i; 42047540Skarels *result = i; 42145914Smckusick return (0); 42245914Smckusick } 4237497Sroot } 42447540Skarels 42547540Skarels /* 42647540Skarels * No space in current array. Expand? 42747540Skarels */ 42847540Skarels if (fdp->fd_nfiles >= lim) 42945914Smckusick return (EMFILE); 43047653Skarels if (fdp->fd_nfiles < NDEXTENT) 43147653Skarels nfiles = NDEXTENT; 43247653Skarels else 43347653Skarels nfiles = 2 * fdp->fd_nfiles; 43447540Skarels MALLOC(newofile, struct file **, nfiles * OFILESIZE, 43547540Skarels M_FILEDESC, M_WAITOK); 43647540Skarels newofileflags = (char *) &newofile[nfiles]; 43747540Skarels /* 43847540Skarels * Copy the existing ofile and ofileflags arrays 43947540Skarels * and zero the new portion of each array. 44047540Skarels */ 44147540Skarels bcopy(fdp->fd_ofiles, newofile, 44247540Skarels (i = sizeof(struct file *) * fdp->fd_nfiles)); 44347540Skarels bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i); 44447540Skarels bcopy(fdp->fd_ofileflags, newofileflags, 44547540Skarels (i = sizeof(char) * fdp->fd_nfiles)); 44647540Skarels bzero(newofileflags + i, nfiles * sizeof(char) - i); 44747653Skarels if (fdp->fd_nfiles > NDFILE) 44847653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 44947540Skarels fdp->fd_ofiles = newofile; 45047540Skarels fdp->fd_ofileflags = newofileflags; 45147540Skarels fdp->fd_nfiles = nfiles; 45247540Skarels fdexpand++; 45339733Smckusick } 4547497Sroot } 4557497Sroot 45642863Smckusick /* 45747653Skarels * Check to see whether n user file descriptors 45847653Skarels * are available to the process p. 45942863Smckusick */ 46047540Skarels fdavail(p, n) 46147540Skarels struct proc *p; 46247540Skarels register int n; 46312748Ssam { 46447540Skarels register struct filedesc *fdp = p->p_fd; 46547653Skarels register struct file **fpp; 46647540Skarels register int i; 46712748Ssam 46847540Skarels if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 && 46947540Skarels (n -= i) <= 0) 47047540Skarels return (1); 47147653Skarels fpp = &fdp->fd_ofiles[fdp->fd_freefile]; 47247653Skarels for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++) 47347653Skarels if (*fpp == NULL && --n <= 0) 47447540Skarels return (1); 47547540Skarels return (0); 47612748Ssam } 47712748Ssam 4787497Sroot /* 47947540Skarels * Create a new open file structure and allocate 48047540Skarels * a file decriptor for the process that refers to it. 4817497Sroot */ 48245914Smckusick falloc(p, resultfp, resultfd) 48345914Smckusick register struct proc *p; 48437728Smckusick struct file **resultfp; 48537728Smckusick int *resultfd; 4867497Sroot { 48749981Smckusick register struct file *fp, *fq, **fpp; 48837728Smckusick int error, i; 4897422Sroot 49047540Skarels if (error = fdalloc(p, 0, &i)) 49137728Smckusick return (error); 49249981Smckusick if (nfiles >= maxfiles) { 49349981Smckusick tablefull("file"); 49449981Smckusick return (ENFILE); 49549981Smckusick } 49649981Smckusick /* 49749981Smckusick * Allocate a new file descriptor. 49849981Smckusick * If the process has file descriptor zero open, add to the list 49949981Smckusick * of open files at that point, otherwise put it at the front of 50049981Smckusick * the list of open files. 50149981Smckusick */ 50249981Smckusick nfiles++; 50349981Smckusick MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK); 50449981Smckusick if (fq = p->p_fd->fd_ofiles[0]) 50549981Smckusick fpp = &fq->f_filef; 50649981Smckusick else 50749981Smckusick fpp = &filehead; 50850129Smckusick p->p_fd->fd_ofiles[i] = fp; 50949981Smckusick if (fq = *fpp) 51049981Smckusick fq->f_fileb = &fp->f_filef; 51149981Smckusick fp->f_filef = fq; 51249981Smckusick fp->f_fileb = fpp; 51349981Smckusick *fpp = fp; 51412748Ssam fp->f_count = 1; 51549981Smckusick fp->f_msgcount = 0; 5167497Sroot fp->f_offset = 0; 51747540Skarels fp->f_cred = p->p_ucred; 51837728Smckusick crhold(fp->f_cred); 51937728Smckusick if (resultfp) 52037728Smckusick *resultfp = fp; 52137728Smckusick if (resultfd) 52237728Smckusick *resultfd = i; 52337728Smckusick return (0); 5247497Sroot } 52512748Ssam 5267497Sroot /* 52749981Smckusick * Free a file descriptor. 52849981Smckusick */ 52949981Smckusick ffree(fp) 53049981Smckusick register struct file *fp; 53149981Smckusick { 53249981Smckusick register struct file *fq; 53349981Smckusick 53449981Smckusick if (fq = fp->f_filef) 53549981Smckusick fq->f_fileb = fp->f_fileb; 53649981Smckusick *fp->f_fileb = fq; 53749981Smckusick crfree(fp->f_cred); 53849981Smckusick #ifdef DIAGNOSTIC 53949981Smckusick fp->f_filef = NULL; 54049981Smckusick fp->f_fileb = NULL; 54149981Smckusick fp->f_count = 0; 54249981Smckusick #endif 54349981Smckusick nfiles--; 54449981Smckusick FREE(fp, M_FILE); 54549981Smckusick } 54649981Smckusick 54749981Smckusick /* 54847540Skarels * Copy a filedesc structure. 54945914Smckusick */ 55045914Smckusick struct filedesc * 55147540Skarels fdcopy(p) 55247540Skarels struct proc *p; 55345914Smckusick { 55447653Skarels register struct filedesc *newfdp, *fdp = p->p_fd; 55547653Skarels register struct file **fpp; 55645914Smckusick register int i; 55745914Smckusick 55847653Skarels MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0), 55947653Skarels M_FILEDESC, M_WAITOK); 56047653Skarels bcopy(fdp, newfdp, sizeof(struct filedesc)); 56145914Smckusick VREF(newfdp->fd_cdir); 56245914Smckusick if (newfdp->fd_rdir) 56345914Smckusick VREF(newfdp->fd_rdir); 56445914Smckusick newfdp->fd_refcnt = 1; 56547540Skarels 56647540Skarels /* 56747653Skarels * If the number of open files fits in the internal arrays 56847653Skarels * of the open file structure, use them, otherwise allocate 56947653Skarels * additional memory for the number of descriptors currently 57047653Skarels * in use. 57147540Skarels */ 57247653Skarels if (newfdp->fd_lastfile < NDFILE) { 57347653Skarels newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles; 57447653Skarels newfdp->fd_ofileflags = 57547653Skarels ((struct filedesc0 *) newfdp)->fd_dfileflags; 57647653Skarels i = NDFILE; 57747653Skarels } else { 57847653Skarels /* 57947653Skarels * Compute the smallest multiple of NDEXTENT needed 58047653Skarels * for the file descriptors currently in use, 58147653Skarels * allowing the table to shrink. 58247653Skarels */ 58347653Skarels i = newfdp->fd_nfiles; 58447653Skarels while (i > 2 * NDEXTENT && i >= newfdp->fd_lastfile * 2) 58547653Skarels i /= 2; 58647653Skarels MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE, 58747653Skarels M_FILEDESC, M_WAITOK); 58847653Skarels newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; 58947653Skarels } 59047540Skarels newfdp->fd_nfiles = i; 59147540Skarels bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **)); 59247540Skarels bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char)); 59347653Skarels fpp = newfdp->fd_ofiles; 59447653Skarels for (i = newfdp->fd_lastfile; i-- >= 0; fpp++) 59547653Skarels if (*fpp != NULL) 59647653Skarels (*fpp)->f_count++; 59745914Smckusick return (newfdp); 59845914Smckusick } 59945914Smckusick 60045914Smckusick /* 60145914Smckusick * Release a filedesc structure. 60245914Smckusick */ 60347653Skarels void 60447540Skarels fdfree(p) 60547540Skarels struct proc *p; 60645914Smckusick { 60747540Skarels register struct filedesc *fdp = p->p_fd; 60847653Skarels struct file **fpp; 60945914Smckusick register int i; 61045914Smckusick 61147540Skarels if (--fdp->fd_refcnt > 0) 61245914Smckusick return; 61347653Skarels fpp = fdp->fd_ofiles; 61447653Skarels for (i = fdp->fd_lastfile; i-- >= 0; fpp++) 61547653Skarels if (*fpp) 61647653Skarels (void) closef(*fpp, p); 61747653Skarels if (fdp->fd_nfiles > NDFILE) 61847653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 61945914Smckusick vrele(fdp->fd_cdir); 62045914Smckusick if (fdp->fd_rdir) 62145914Smckusick vrele(fdp->fd_rdir); 62247540Skarels FREE(fdp, M_FILEDESC); 62345914Smckusick } 62445914Smckusick 62545914Smckusick /* 6267497Sroot * Internal form of close. 62712748Ssam * Decrement reference count on file structure. 62852034Skarels * Note: p may be NULL when closing a file 62952034Skarels * that was being passed in a message. 6307497Sroot */ 63147540Skarels closef(fp, p) 6327497Sroot register struct file *fp; 63349981Smckusick register struct proc *p; 6347497Sroot { 63553538Sheideman USES_VOP_ADVLOCK; 63646200Smckusick struct vnode *vp; 63746200Smckusick struct flock lf; 63839354Smckusick int error; 6397497Sroot 6407422Sroot if (fp == NULL) 64139354Smckusick return (0); 64246200Smckusick /* 64346200Smckusick * POSIX record locking dictates that any close releases ALL 64446200Smckusick * locks owned by this process. This is handled by setting 64546200Smckusick * a flag in the unlock to free ONLY locks obeying POSIX 64646200Smckusick * semantics, and not to free BSD-style file locks. 64752034Skarels * If the descriptor was in a message, POSIX-style locks 64852034Skarels * aren't passed with the descriptor. 64946200Smckusick */ 65052034Skarels if (p && (p->p_flag & SADVLCK) && fp->f_type == DTYPE_VNODE) { 65146200Smckusick lf.l_whence = SEEK_SET; 65246200Smckusick lf.l_start = 0; 65346200Smckusick lf.l_len = 0; 65446200Smckusick lf.l_type = F_UNLCK; 65546200Smckusick vp = (struct vnode *)fp->f_data; 65648029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX); 65746200Smckusick } 65847540Skarels if (--fp->f_count > 0) 65939354Smckusick return (0); 66047540Skarels if (fp->f_count < 0) 66147540Skarels panic("closef: count < 0"); 66249951Smckusick if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) { 66349951Smckusick lf.l_whence = SEEK_SET; 66449951Smckusick lf.l_start = 0; 66549951Smckusick lf.l_len = 0; 66649951Smckusick lf.l_type = F_UNLCK; 66749951Smckusick vp = (struct vnode *)fp->f_data; 66848029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); 66949951Smckusick } 67048029Smckusick error = (*fp->f_ops->fo_close)(fp, p); 67149981Smckusick ffree(fp); 67239354Smckusick return (error); 6737422Sroot } 67413044Ssam 67513044Ssam /* 67613044Ssam * Apply an advisory lock on a file descriptor. 67746200Smckusick * 67846200Smckusick * Just attempt to get a record lock of the requested type on 67946200Smckusick * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). 68013044Ssam */ 68146200Smckusick 68242863Smckusick /* ARGSUSED */ 68342863Smckusick flock(p, uap, retval) 68442863Smckusick struct proc *p; 68542863Smckusick register struct args { 68647540Skarels int fd; 68713044Ssam int how; 68842863Smckusick } *uap; 68942863Smckusick int *retval; 69042863Smckusick { 69153538Sheideman USES_VOP_ADVLOCK; 69245914Smckusick register struct filedesc *fdp = p->p_fd; 69313044Ssam register struct file *fp; 69446200Smckusick struct vnode *vp; 69546200Smckusick struct flock lf; 69646200Smckusick int error; 69713044Ssam 69847540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 69947653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 70044404Skarels return (EBADF); 70142863Smckusick if (fp->f_type != DTYPE_VNODE) 70244404Skarels return (EOPNOTSUPP); 70346200Smckusick vp = (struct vnode *)fp->f_data; 70446200Smckusick lf.l_whence = SEEK_SET; 70546200Smckusick lf.l_start = 0; 70646200Smckusick lf.l_len = 0; 70713101Ssam if (uap->how & LOCK_UN) { 70846200Smckusick lf.l_type = F_UNLCK; 70949951Smckusick fp->f_flag &= ~FHASLOCK; 71048029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK)); 71113044Ssam } 71217998Skarels if (uap->how & LOCK_EX) 71346200Smckusick lf.l_type = F_WRLCK; 71446200Smckusick else if (uap->how & LOCK_SH) 71546200Smckusick lf.l_type = F_RDLCK; 71646200Smckusick else 71746200Smckusick return (EBADF); 71849951Smckusick fp->f_flag |= FHASLOCK; 71946200Smckusick if (uap->how & LOCK_NB) 72048029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK)); 72148029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); 72213044Ssam } 72337586Smarc 72437586Smarc /* 72537586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 72637586Smarc * 72737586Smarc * Opening minor device N dup()s the file (if any) connected to file 72837586Smarc * descriptor N belonging to the calling process. Note that this driver 72937586Smarc * consists of only the ``open()'' routine, because all subsequent 73037586Smarc * references to this file will be direct to the other driver. 73137586Smarc */ 73237728Smckusick /* ARGSUSED */ 73352568Smckusick fdopen(dev, mode, type, p) 73437586Smarc dev_t dev; 73537728Smckusick int mode, type; 73652568Smckusick struct proc *p; 73737586Smarc { 73837586Smarc 73937586Smarc /* 74047540Skarels * XXX Kludge: set curproc->p_dupfd to contain the value of the 74143406Smckusick * the file descriptor being sought for duplication. The error 74243406Smckusick * return ensures that the vnode for this device will be released 74343406Smckusick * by vn_open. Open will detect this special error and take the 74443406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN 74543406Smckusick * will simply report the error. 74637586Smarc */ 74752568Smckusick p->p_dupfd = minor(dev); 74843406Smckusick return (ENODEV); 74943406Smckusick } 75040873Sbostic 75143406Smckusick /* 75243406Smckusick * Duplicate the specified descriptor to a free descriptor. 75343406Smckusick */ 75453826Spendry dupfdopen(fdp, indx, dfd, mode, error) 75545914Smckusick register struct filedesc *fdp; 75643406Smckusick register int indx, dfd; 75743406Smckusick int mode; 75853826Spendry int error; 75943406Smckusick { 76043406Smckusick register struct file *wfp; 76143406Smckusick struct file *fp; 76243406Smckusick 76337586Smarc /* 76443406Smckusick * If the to-be-dup'd fd number is greater than the allowed number 76543406Smckusick * of file descriptors, or the fd to be dup'd has already been 76643406Smckusick * closed, reject. Note, check for new == old is necessary as 76743406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor 76843406Smckusick * as the new descriptor. 76937586Smarc */ 77047653Skarels fp = fdp->fd_ofiles[indx]; 77147653Skarels if ((u_int)dfd >= fdp->fd_nfiles || 77247653Skarels (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp) 77337586Smarc return (EBADF); 77440873Sbostic 77537586Smarc /* 77653826Spendry * There are two cases of interest here. 77753826Spendry * 77853826Spendry * For ENODEV simply dup (dfd) to file descriptor 77953826Spendry * (indx) and return. 78053826Spendry * 78153826Spendry * For ENXIO steal away the file structure from (dfd) and 78253826Spendry * store it in (indx). (dfd) is effectively closed by 78353826Spendry * this operation. 78453826Spendry * 78553826Spendry * Any other error code is just returned. 78637586Smarc */ 78753826Spendry switch (error) { 78853826Spendry case ENODEV: 78953826Spendry /* 79053826Spendry * Check that the mode the file is being opened for is a 79153826Spendry * subset of the mode of the existing descriptor. 79253826Spendry */ 79353826Spendry if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) 79453826Spendry return (EACCES); 79553826Spendry fdp->fd_ofiles[indx] = wfp; 79653826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 79753826Spendry wfp->f_count++; 79853826Spendry if (indx > fdp->fd_lastfile) 79953826Spendry fdp->fd_lastfile = indx; 80053826Spendry return (0); 80153826Spendry 80253826Spendry case ENXIO: 80353826Spendry /* 80453826Spendry * Steal away the file pointer from dfd, and stuff it into indx. 80553826Spendry */ 80653826Spendry fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd]; 80753826Spendry fdp->fd_ofiles[dfd] = NULL; 80853826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 80953826Spendry fdp->fd_ofileflags[dfd] = 0; 81053826Spendry /* 81153826Spendry * Complete the clean up of the filedesc structure by 81253826Spendry * recomputing the various hints. 81353826Spendry */ 81453826Spendry if (indx > fdp->fd_lastfile) 81553826Spendry fdp->fd_lastfile = indx; 81653826Spendry else 81753826Spendry while (fdp->fd_lastfile > 0 && 81853826Spendry fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 81953826Spendry fdp->fd_lastfile--; 82053826Spendry if (dfd < fdp->fd_freefile) 82153826Spendry fdp->fd_freefile = dfd; 82253826Spendry return (0); 82353826Spendry 82453826Spendry default: 82553826Spendry return (error); 82653826Spendry } 82753826Spendry /* NOTREACHED */ 82837586Smarc } 829