123367Smckusick /* 263170Sbostic * Copyright (c) 1982, 1986, 1989, 1991, 1993 363170Sbostic * The Regents of the University of California. All rights reserved. 4*65771Sbostic * (c) UNIX System Laboratories, Inc. 5*65771Sbostic * All or some portions of this file are derived from material licensed 6*65771Sbostic * to the University of California by American Telephone and Telegraph 7*65771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8*65771Sbostic * the permission of UNIX System Laboratories, Inc. 923367Smckusick * 1044431Sbostic * %sccs.include.redist.c% 1137728Smckusick * 12*65771Sbostic * @(#)kern_descrip.c 8.5 (Berkeley) 01/21/94 1323367Smckusick */ 147422Sroot 1556517Sbostic #include <sys/param.h> 1656517Sbostic #include <sys/systm.h> 1756517Sbostic #include <sys/filedesc.h> 1856517Sbostic #include <sys/kernel.h> 1956517Sbostic #include <sys/vnode.h> 2056517Sbostic #include <sys/proc.h> 2156517Sbostic #include <sys/file.h> 2256517Sbostic #include <sys/socket.h> 2356517Sbostic #include <sys/socketvar.h> 2456517Sbostic #include <sys/stat.h> 2556517Sbostic #include <sys/ioctl.h> 2656517Sbostic #include <sys/fcntl.h> 2756517Sbostic #include <sys/malloc.h> 2856517Sbostic #include <sys/syslog.h> 2960413Smckusick #include <sys/unistd.h> 3056517Sbostic #include <sys/resourcevar.h> 317497Sroot 327422Sroot /* 337497Sroot * Descriptor management. 347422Sroot */ 3549981Smckusick struct file *filehead; /* head of list of open files */ 3649981Smckusick int nfiles; /* actual number of open files */ 377497Sroot 387497Sroot /* 397497Sroot * System calls on descriptors. 407497Sroot */ 4154934Storek struct getdtablesize_args { 4254934Storek int dummy; 4354934Storek }; 4442863Smckusick /* ARGSUSED */ 4542863Smckusick getdtablesize(p, uap, retval) 4642863Smckusick struct proc *p; 4754934Storek struct getdtablesize_args *uap; 4842863Smckusick int *retval; 497497Sroot { 507497Sroot 5158775Smckusick *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); 5244404Skarels return (0); 537497Sroot } 547497Sroot 5542863Smckusick /* 5642863Smckusick * Duplicate a file descriptor. 5742863Smckusick */ 5854934Storek struct dup_args { 5958775Smckusick u_int fd; 6054934Storek }; 6142863Smckusick /* ARGSUSED */ 6242863Smckusick dup(p, uap, retval) 6342863Smckusick struct proc *p; 6454934Storek struct dup_args *uap; 6542863Smckusick int *retval; 667422Sroot { 6758775Smckusick register struct filedesc *fdp; 6858775Smckusick u_int old; 6958775Smckusick int new, error; 707497Sroot 7158775Smckusick old = uap->fd; 7242863Smckusick /* 7342863Smckusick * XXX Compatibility 7442863Smckusick */ 7558775Smckusick if (old &~ 077) { uap->fd &= 077; return (dup2(p, uap, retval)); } 767497Sroot 7758775Smckusick fdp = p->p_fd; 7858775Smckusick if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL) 7944404Skarels return (EBADF); 8058775Smckusick if (error = fdalloc(p, 0, &new)) 8144404Skarels return (error); 8258775Smckusick return (finishdup(fdp, (int)old, new, retval)); 837497Sroot } 847497Sroot 8542863Smckusick /* 8642863Smckusick * Duplicate a file descriptor to a particular value. 8742863Smckusick */ 8854934Storek struct dup2_args { 8954934Storek u_int from; 9054934Storek u_int to; 9154934Storek }; 9242863Smckusick /* ARGSUSED */ 9342863Smckusick dup2(p, uap, retval) 9442863Smckusick struct proc *p; 9554934Storek struct dup2_args *uap; 9642863Smckusick int *retval; 977497Sroot { 9845914Smckusick register struct filedesc *fdp = p->p_fd; 9947653Skarels register u_int old = uap->from, new = uap->to; 10045914Smckusick int i, error; 1017422Sroot 10247653Skarels if (old >= fdp->fd_nfiles || 10358775Smckusick fdp->fd_ofiles[old] == NULL || 10458656Smckusick new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || 10558775Smckusick new >= maxfiles) 10644404Skarels return (EBADF); 10758775Smckusick if (old == new) { 10858775Smckusick *retval = new; 10944404Skarels return (0); 11058775Smckusick } 11147653Skarels if (new >= fdp->fd_nfiles) { 11247653Skarels if (error = fdalloc(p, new, &i)) 11345914Smckusick return (error); 11447653Skarels if (new != i) 11547540Skarels panic("dup2: fdalloc"); 11647653Skarels } else if (fdp->fd_ofiles[new]) { 11747653Skarels if (fdp->fd_ofileflags[new] & UF_MAPPED) 11847653Skarels (void) munmapfd(p, new); 11947653Skarels /* 12047653Skarels * dup2() must succeed even if the close has an error. 12147653Skarels */ 12247653Skarels (void) closef(fdp->fd_ofiles[new], p); 1237422Sroot } 12458775Smckusick return (finishdup(fdp, (int)old, (int)new, retval)); 1257696Ssam } 1267696Ssam 12712748Ssam /* 12812748Ssam * The file control system call. 12912748Ssam */ 13054934Storek struct fcntl_args { 13154934Storek int fd; 13254934Storek int cmd; 13354934Storek int arg; 13454934Storek }; 13542863Smckusick /* ARGSUSED */ 13642863Smckusick fcntl(p, uap, retval) 13742863Smckusick struct proc *p; 13854934Storek register struct fcntl_args *uap; 13942863Smckusick int *retval; 14042863Smckusick { 14145914Smckusick register struct filedesc *fdp = p->p_fd; 14242863Smckusick register struct file *fp; 14312748Ssam register char *pop; 14446200Smckusick struct vnode *vp; 14548029Smckusick int i, tmp, error, flg = F_POSIX; 14646200Smckusick struct flock fl; 14758775Smckusick u_int newmin; 1487497Sroot 14947540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 15047653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 15144404Skarels return (EBADF); 15247653Skarels pop = &fdp->fd_ofileflags[uap->fd]; 15358775Smckusick switch (uap->cmd) { 15458775Smckusick 15515076Skarels case F_DUPFD: 15658775Smckusick newmin = uap->arg; 15758775Smckusick if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || 15858775Smckusick newmin >= maxfiles) 15944404Skarels return (EINVAL); 16058775Smckusick if (error = fdalloc(p, newmin, &i)) 16144404Skarels return (error); 16258775Smckusick return (finishdup(fdp, uap->fd, i, retval)); 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); 23764593Sbostic p->p_flag |= P_ADVLOCK; 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); 24364593Sbostic p->p_flag |= P_ADVLOCK; 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 /* 27558775Smckusick * Common code for dup, dup2, and fcntl(F_DUPFD). 27658775Smckusick */ 27758775Smckusick int 27858775Smckusick finishdup(fdp, old, new, retval) 27958775Smckusick register struct filedesc *fdp; 28058775Smckusick register int old, new, *retval; 28158775Smckusick { 28258775Smckusick register struct file *fp; 28358775Smckusick 28458775Smckusick fp = fdp->fd_ofiles[old]; 28558775Smckusick fdp->fd_ofiles[new] = fp; 28658775Smckusick fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; 28758775Smckusick fp->f_count++; 28858775Smckusick if (new > fdp->fd_lastfile) 28958775Smckusick fdp->fd_lastfile = new; 29058775Smckusick *retval = new; 29158775Smckusick return (0); 29258775Smckusick } 29358775Smckusick 29458775Smckusick /* 29542863Smckusick * Close a file descriptor. 29642863Smckusick */ 29754934Storek struct close_args { 29854934Storek int fd; 29954934Storek }; 30042863Smckusick /* ARGSUSED */ 30142863Smckusick close(p, uap, retval) 30242863Smckusick struct proc *p; 30354934Storek struct close_args *uap; 30442863Smckusick int *retval; 3058029Sroot { 30645914Smckusick register struct filedesc *fdp = p->p_fd; 30712748Ssam register struct file *fp; 30847540Skarels register int fd = uap->fd; 30913044Ssam register u_char *pf; 3108029Sroot 31147540Skarels if ((unsigned)fd >= fdp->fd_nfiles || 31247653Skarels (fp = fdp->fd_ofiles[fd]) == NULL) 31344404Skarels return (EBADF); 31447653Skarels pf = (u_char *)&fdp->fd_ofileflags[fd]; 31513044Ssam if (*pf & UF_MAPPED) 31647540Skarels (void) munmapfd(p, fd); 31747653Skarels fdp->fd_ofiles[fd] = NULL; 31847653Skarels while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 31945914Smckusick fdp->fd_lastfile--; 32047540Skarels if (fd < fdp->fd_freefile) 32147540Skarels fdp->fd_freefile = fd; 32215550Skarels *pf = 0; 32347540Skarels return (closef(fp, p)); 3248029Sroot } 3258029Sroot 32654346Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 32742863Smckusick /* 32842863Smckusick * Return status information about a file descriptor. 32942863Smckusick */ 33054934Storek struct ofstat_args { 33154934Storek int fd; 33254934Storek struct ostat *sb; 33354934Storek }; 33442863Smckusick /* ARGSUSED */ 33553758Smckusick ofstat(p, uap, retval) 33642863Smckusick struct proc *p; 33754934Storek register struct ofstat_args *uap; 33853466Smckusick int *retval; 33953466Smckusick { 34053466Smckusick register struct filedesc *fdp = p->p_fd; 34153466Smckusick register struct file *fp; 34253466Smckusick struct stat ub; 34353466Smckusick struct ostat oub; 34453466Smckusick int error; 34553466Smckusick 34653466Smckusick if ((unsigned)uap->fd >= fdp->fd_nfiles || 34753466Smckusick (fp = fdp->fd_ofiles[uap->fd]) == NULL) 34853466Smckusick return (EBADF); 34953466Smckusick switch (fp->f_type) { 35053466Smckusick 35153466Smckusick case DTYPE_VNODE: 35253466Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p); 35353466Smckusick break; 35453466Smckusick 35553466Smckusick case DTYPE_SOCKET: 35653466Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 35753466Smckusick break; 35853466Smckusick 35953466Smckusick default: 36054346Smckusick panic("ofstat"); 36153466Smckusick /*NOTREACHED*/ 36253466Smckusick } 36353466Smckusick cvtstat(&ub, &oub); 36453466Smckusick if (error == 0) 36553466Smckusick error = copyout((caddr_t)&oub, (caddr_t)uap->sb, sizeof (oub)); 36653466Smckusick return (error); 36753466Smckusick } 36854346Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 36953466Smckusick 37053466Smckusick /* 37153466Smckusick * Return status information about a file descriptor. 37253466Smckusick */ 37354934Storek struct fstat_args { 37454934Storek int fd; 37554934Storek struct stat *sb; 37654934Storek }; 37753466Smckusick /* ARGSUSED */ 37853758Smckusick fstat(p, uap, retval) 37953466Smckusick struct proc *p; 38054934Storek register struct fstat_args *uap; 38142863Smckusick int *retval; 38213044Ssam { 38345914Smckusick register struct filedesc *fdp = p->p_fd; 38413044Ssam register struct file *fp; 38513044Ssam struct stat ub; 38642863Smckusick int error; 38713044Ssam 38847540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 38947653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 39044404Skarels return (EBADF); 39113044Ssam switch (fp->f_type) { 39213044Ssam 39337728Smckusick case DTYPE_VNODE: 39448029Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p); 39513044Ssam break; 39613044Ssam 39713044Ssam case DTYPE_SOCKET: 39842863Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 39913044Ssam break; 40013044Ssam 40113044Ssam default: 40213044Ssam panic("fstat"); 40313044Ssam /*NOTREACHED*/ 40413044Ssam } 40542863Smckusick if (error == 0) 40642863Smckusick error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); 40744404Skarels return (error); 40813044Ssam } 40913044Ssam 4107422Sroot /* 41160413Smckusick * Return pathconf information about a file descriptor. 41260413Smckusick */ 41360413Smckusick struct fpathconf_args { 41460413Smckusick int fd; 41560413Smckusick int name; 41660413Smckusick }; 41760413Smckusick /* ARGSUSED */ 41860413Smckusick fpathconf(p, uap, retval) 41960413Smckusick struct proc *p; 42060413Smckusick register struct fpathconf_args *uap; 42160413Smckusick int *retval; 42260413Smckusick { 42360413Smckusick struct filedesc *fdp = p->p_fd; 42460413Smckusick struct file *fp; 42560413Smckusick struct vnode *vp; 42660413Smckusick 42760413Smckusick if ((unsigned)uap->fd >= fdp->fd_nfiles || 42860413Smckusick (fp = fdp->fd_ofiles[uap->fd]) == NULL) 42960413Smckusick return (EBADF); 43060413Smckusick switch (fp->f_type) { 43160413Smckusick 43260413Smckusick case DTYPE_SOCKET: 43360413Smckusick if (uap->name != _PC_PIPE_BUF) 43460413Smckusick return (EINVAL); 43560413Smckusick *retval = PIPE_BUF; 43660413Smckusick return (0); 43760413Smckusick 43860413Smckusick case DTYPE_VNODE: 43960413Smckusick vp = (struct vnode *)fp->f_data; 44060413Smckusick return (VOP_PATHCONF(vp, uap->name, retval)); 44160413Smckusick 44260413Smckusick default: 44360413Smckusick panic("fpathconf"); 44460413Smckusick } 44560413Smckusick /*NOTREACHED*/ 44660413Smckusick } 44760413Smckusick 44860413Smckusick /* 44947540Skarels * Allocate a file descriptor for the process. 4507422Sroot */ 45147540Skarels int fdexpand; 45245914Smckusick 45347540Skarels fdalloc(p, want, result) 45447540Skarels struct proc *p; 45547540Skarels int want; 45637728Smckusick int *result; 4577422Sroot { 45847540Skarels register struct filedesc *fdp = p->p_fd; 45947540Skarels register int i; 46047540Skarels int lim, last, nfiles; 46145914Smckusick struct file **newofile; 46245914Smckusick char *newofileflags; 4637497Sroot 46447540Skarels /* 46547540Skarels * Search for a free descriptor starting at the higher 46647540Skarels * of want or fd_freefile. If that fails, consider 46747540Skarels * expanding the ofile array. 46847540Skarels */ 46958775Smckusick lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); 47045914Smckusick for (;;) { 47147540Skarels last = min(fdp->fd_nfiles, lim); 47247540Skarels if ((i = want) < fdp->fd_freefile) 47347540Skarels i = fdp->fd_freefile; 47447540Skarels for (; i < last; i++) { 47547653Skarels if (fdp->fd_ofiles[i] == NULL) { 47647653Skarels fdp->fd_ofileflags[i] = 0; 47747540Skarels if (i > fdp->fd_lastfile) 47847540Skarels fdp->fd_lastfile = i; 47947653Skarels if (want <= fdp->fd_freefile) 48047540Skarels fdp->fd_freefile = i; 48147540Skarels *result = i; 48245914Smckusick return (0); 48345914Smckusick } 4847497Sroot } 48547540Skarels 48647540Skarels /* 48747540Skarels * No space in current array. Expand? 48847540Skarels */ 48947540Skarels if (fdp->fd_nfiles >= lim) 49045914Smckusick return (EMFILE); 49147653Skarels if (fdp->fd_nfiles < NDEXTENT) 49247653Skarels nfiles = NDEXTENT; 49347653Skarels else 49447653Skarels nfiles = 2 * fdp->fd_nfiles; 49547540Skarels MALLOC(newofile, struct file **, nfiles * OFILESIZE, 49647540Skarels M_FILEDESC, M_WAITOK); 49747540Skarels newofileflags = (char *) &newofile[nfiles]; 49847540Skarels /* 49947540Skarels * Copy the existing ofile and ofileflags arrays 50047540Skarels * and zero the new portion of each array. 50147540Skarels */ 50247540Skarels bcopy(fdp->fd_ofiles, newofile, 50347540Skarels (i = sizeof(struct file *) * fdp->fd_nfiles)); 50447540Skarels bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i); 50547540Skarels bcopy(fdp->fd_ofileflags, newofileflags, 50647540Skarels (i = sizeof(char) * fdp->fd_nfiles)); 50747540Skarels bzero(newofileflags + i, nfiles * sizeof(char) - i); 50847653Skarels if (fdp->fd_nfiles > NDFILE) 50947653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 51047540Skarels fdp->fd_ofiles = newofile; 51147540Skarels fdp->fd_ofileflags = newofileflags; 51247540Skarels fdp->fd_nfiles = nfiles; 51347540Skarels fdexpand++; 51439733Smckusick } 5157497Sroot } 5167497Sroot 51742863Smckusick /* 51847653Skarels * Check to see whether n user file descriptors 51947653Skarels * are available to the process p. 52042863Smckusick */ 52147540Skarels fdavail(p, n) 52247540Skarels struct proc *p; 52347540Skarels register int n; 52412748Ssam { 52547540Skarels register struct filedesc *fdp = p->p_fd; 52647653Skarels register struct file **fpp; 52758775Smckusick register int i, lim; 52812748Ssam 52958775Smckusick lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); 53058775Smckusick if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0) 53147540Skarels return (1); 53247653Skarels fpp = &fdp->fd_ofiles[fdp->fd_freefile]; 53347653Skarels for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++) 53447653Skarels if (*fpp == NULL && --n <= 0) 53547540Skarels return (1); 53647540Skarels return (0); 53712748Ssam } 53812748Ssam 5397497Sroot /* 54047540Skarels * Create a new open file structure and allocate 54147540Skarels * a file decriptor for the process that refers to it. 5427497Sroot */ 54345914Smckusick falloc(p, resultfp, resultfd) 54445914Smckusick register struct proc *p; 54537728Smckusick struct file **resultfp; 54637728Smckusick int *resultfd; 5477497Sroot { 54849981Smckusick register struct file *fp, *fq, **fpp; 54937728Smckusick int error, i; 5507422Sroot 55147540Skarels if (error = fdalloc(p, 0, &i)) 55237728Smckusick return (error); 55349981Smckusick if (nfiles >= maxfiles) { 55449981Smckusick tablefull("file"); 55549981Smckusick return (ENFILE); 55649981Smckusick } 55749981Smckusick /* 55849981Smckusick * Allocate a new file descriptor. 55949981Smckusick * If the process has file descriptor zero open, add to the list 56049981Smckusick * of open files at that point, otherwise put it at the front of 56149981Smckusick * the list of open files. 56249981Smckusick */ 56349981Smckusick nfiles++; 56449981Smckusick MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK); 56549981Smckusick if (fq = p->p_fd->fd_ofiles[0]) 56649981Smckusick fpp = &fq->f_filef; 56749981Smckusick else 56849981Smckusick fpp = &filehead; 56950129Smckusick p->p_fd->fd_ofiles[i] = fp; 57049981Smckusick if (fq = *fpp) 57149981Smckusick fq->f_fileb = &fp->f_filef; 57249981Smckusick fp->f_filef = fq; 57349981Smckusick fp->f_fileb = fpp; 57449981Smckusick *fpp = fp; 57512748Ssam fp->f_count = 1; 57649981Smckusick fp->f_msgcount = 0; 5777497Sroot fp->f_offset = 0; 57847540Skarels fp->f_cred = p->p_ucred; 57937728Smckusick crhold(fp->f_cred); 58037728Smckusick if (resultfp) 58137728Smckusick *resultfp = fp; 58237728Smckusick if (resultfd) 58337728Smckusick *resultfd = i; 58437728Smckusick return (0); 5857497Sroot } 58612748Ssam 5877497Sroot /* 58849981Smckusick * Free a file descriptor. 58949981Smckusick */ 59049981Smckusick ffree(fp) 59149981Smckusick register struct file *fp; 59249981Smckusick { 59349981Smckusick register struct file *fq; 59449981Smckusick 59549981Smckusick if (fq = fp->f_filef) 59649981Smckusick fq->f_fileb = fp->f_fileb; 59749981Smckusick *fp->f_fileb = fq; 59849981Smckusick crfree(fp->f_cred); 59949981Smckusick #ifdef DIAGNOSTIC 60049981Smckusick fp->f_filef = NULL; 60149981Smckusick fp->f_fileb = NULL; 60249981Smckusick fp->f_count = 0; 60349981Smckusick #endif 60449981Smckusick nfiles--; 60549981Smckusick FREE(fp, M_FILE); 60649981Smckusick } 60749981Smckusick 60849981Smckusick /* 60947540Skarels * Copy a filedesc structure. 61045914Smckusick */ 61145914Smckusick struct filedesc * 61247540Skarels fdcopy(p) 61347540Skarels struct proc *p; 61445914Smckusick { 61547653Skarels register struct filedesc *newfdp, *fdp = p->p_fd; 61647653Skarels register struct file **fpp; 61745914Smckusick register int i; 61845914Smckusick 61947653Skarels MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0), 62047653Skarels M_FILEDESC, M_WAITOK); 62147653Skarels bcopy(fdp, newfdp, sizeof(struct filedesc)); 62245914Smckusick VREF(newfdp->fd_cdir); 62345914Smckusick if (newfdp->fd_rdir) 62445914Smckusick VREF(newfdp->fd_rdir); 62545914Smckusick newfdp->fd_refcnt = 1; 62647540Skarels 62747540Skarels /* 62847653Skarels * If the number of open files fits in the internal arrays 62947653Skarels * of the open file structure, use them, otherwise allocate 63047653Skarels * additional memory for the number of descriptors currently 63147653Skarels * in use. 63247540Skarels */ 63347653Skarels if (newfdp->fd_lastfile < NDFILE) { 63447653Skarels newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles; 63547653Skarels newfdp->fd_ofileflags = 63647653Skarels ((struct filedesc0 *) newfdp)->fd_dfileflags; 63747653Skarels i = NDFILE; 63847653Skarels } else { 63947653Skarels /* 64047653Skarels * Compute the smallest multiple of NDEXTENT needed 64147653Skarels * for the file descriptors currently in use, 64247653Skarels * allowing the table to shrink. 64347653Skarels */ 64447653Skarels i = newfdp->fd_nfiles; 64565547Smckusick while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2) 64647653Skarels i /= 2; 64747653Skarels MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE, 64847653Skarels M_FILEDESC, M_WAITOK); 64947653Skarels newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; 65047653Skarels } 65147540Skarels newfdp->fd_nfiles = i; 65247540Skarels bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **)); 65347540Skarels bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char)); 65447653Skarels fpp = newfdp->fd_ofiles; 65547653Skarels for (i = newfdp->fd_lastfile; i-- >= 0; fpp++) 65647653Skarels if (*fpp != NULL) 65747653Skarels (*fpp)->f_count++; 65845914Smckusick return (newfdp); 65945914Smckusick } 66045914Smckusick 66145914Smckusick /* 66245914Smckusick * Release a filedesc structure. 66345914Smckusick */ 66447653Skarels void 66547540Skarels fdfree(p) 66647540Skarels struct proc *p; 66745914Smckusick { 66847540Skarels register struct filedesc *fdp = p->p_fd; 66947653Skarels struct file **fpp; 67045914Smckusick register int i; 67145914Smckusick 67247540Skarels if (--fdp->fd_refcnt > 0) 67345914Smckusick return; 67447653Skarels fpp = fdp->fd_ofiles; 67547653Skarels for (i = fdp->fd_lastfile; i-- >= 0; fpp++) 67647653Skarels if (*fpp) 67747653Skarels (void) closef(*fpp, p); 67847653Skarels if (fdp->fd_nfiles > NDFILE) 67947653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 68045914Smckusick vrele(fdp->fd_cdir); 68145914Smckusick if (fdp->fd_rdir) 68245914Smckusick vrele(fdp->fd_rdir); 68347540Skarels FREE(fdp, M_FILEDESC); 68445914Smckusick } 68545914Smckusick 68645914Smckusick /* 6877497Sroot * Internal form of close. 68812748Ssam * Decrement reference count on file structure. 68952034Skarels * Note: p may be NULL when closing a file 69052034Skarels * that was being passed in a message. 6917497Sroot */ 69247540Skarels closef(fp, p) 6937497Sroot register struct file *fp; 69449981Smckusick register struct proc *p; 6957497Sroot { 69646200Smckusick struct vnode *vp; 69746200Smckusick struct flock lf; 69839354Smckusick int error; 6997497Sroot 7007422Sroot if (fp == NULL) 70139354Smckusick return (0); 70246200Smckusick /* 70346200Smckusick * POSIX record locking dictates that any close releases ALL 70446200Smckusick * locks owned by this process. This is handled by setting 70546200Smckusick * a flag in the unlock to free ONLY locks obeying POSIX 70646200Smckusick * semantics, and not to free BSD-style file locks. 70752034Skarels * If the descriptor was in a message, POSIX-style locks 70852034Skarels * aren't passed with the descriptor. 70946200Smckusick */ 71064593Sbostic if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) { 71146200Smckusick lf.l_whence = SEEK_SET; 71246200Smckusick lf.l_start = 0; 71346200Smckusick lf.l_len = 0; 71446200Smckusick lf.l_type = F_UNLCK; 71546200Smckusick vp = (struct vnode *)fp->f_data; 71648029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX); 71746200Smckusick } 71847540Skarels if (--fp->f_count > 0) 71939354Smckusick return (0); 72047540Skarels if (fp->f_count < 0) 72147540Skarels panic("closef: count < 0"); 72249951Smckusick if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) { 72349951Smckusick lf.l_whence = SEEK_SET; 72449951Smckusick lf.l_start = 0; 72549951Smckusick lf.l_len = 0; 72649951Smckusick lf.l_type = F_UNLCK; 72749951Smckusick vp = (struct vnode *)fp->f_data; 72848029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); 72949951Smckusick } 73048029Smckusick error = (*fp->f_ops->fo_close)(fp, p); 73149981Smckusick ffree(fp); 73239354Smckusick return (error); 7337422Sroot } 73413044Ssam 73513044Ssam /* 73613044Ssam * Apply an advisory lock on a file descriptor. 73746200Smckusick * 73846200Smckusick * Just attempt to get a record lock of the requested type on 73946200Smckusick * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). 74013044Ssam */ 74154934Storek struct flock_args { 74254934Storek int fd; 74354934Storek int how; 74454934Storek }; 74542863Smckusick /* ARGSUSED */ 74642863Smckusick flock(p, uap, retval) 74742863Smckusick struct proc *p; 74854934Storek register struct flock_args *uap; 74942863Smckusick int *retval; 75042863Smckusick { 75145914Smckusick register struct filedesc *fdp = p->p_fd; 75213044Ssam register struct file *fp; 75346200Smckusick struct vnode *vp; 75446200Smckusick struct flock lf; 75513044Ssam 75647540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 75747653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 75844404Skarels return (EBADF); 75942863Smckusick if (fp->f_type != DTYPE_VNODE) 76044404Skarels return (EOPNOTSUPP); 76146200Smckusick vp = (struct vnode *)fp->f_data; 76246200Smckusick lf.l_whence = SEEK_SET; 76346200Smckusick lf.l_start = 0; 76446200Smckusick lf.l_len = 0; 76513101Ssam if (uap->how & LOCK_UN) { 76646200Smckusick lf.l_type = F_UNLCK; 76749951Smckusick fp->f_flag &= ~FHASLOCK; 76848029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK)); 76913044Ssam } 77017998Skarels if (uap->how & LOCK_EX) 77146200Smckusick lf.l_type = F_WRLCK; 77246200Smckusick else if (uap->how & LOCK_SH) 77346200Smckusick lf.l_type = F_RDLCK; 77446200Smckusick else 77546200Smckusick return (EBADF); 77649951Smckusick fp->f_flag |= FHASLOCK; 77746200Smckusick if (uap->how & LOCK_NB) 77848029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK)); 77948029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); 78013044Ssam } 78137586Smarc 78237586Smarc /* 78337586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 78437586Smarc * 78537586Smarc * Opening minor device N dup()s the file (if any) connected to file 78637586Smarc * descriptor N belonging to the calling process. Note that this driver 78737586Smarc * consists of only the ``open()'' routine, because all subsequent 78837586Smarc * references to this file will be direct to the other driver. 78937586Smarc */ 79037728Smckusick /* ARGSUSED */ 79152568Smckusick fdopen(dev, mode, type, p) 79237586Smarc dev_t dev; 79337728Smckusick int mode, type; 79452568Smckusick struct proc *p; 79537586Smarc { 79637586Smarc 79737586Smarc /* 79847540Skarels * XXX Kludge: set curproc->p_dupfd to contain the value of the 79943406Smckusick * the file descriptor being sought for duplication. The error 80043406Smckusick * return ensures that the vnode for this device will be released 80143406Smckusick * by vn_open. Open will detect this special error and take the 80243406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN 80343406Smckusick * will simply report the error. 80437586Smarc */ 80552568Smckusick p->p_dupfd = minor(dev); 80643406Smckusick return (ENODEV); 80743406Smckusick } 80840873Sbostic 80943406Smckusick /* 81043406Smckusick * Duplicate the specified descriptor to a free descriptor. 81143406Smckusick */ 81253826Spendry dupfdopen(fdp, indx, dfd, mode, error) 81345914Smckusick register struct filedesc *fdp; 81443406Smckusick register int indx, dfd; 81543406Smckusick int mode; 81653826Spendry int error; 81743406Smckusick { 81843406Smckusick register struct file *wfp; 81943406Smckusick struct file *fp; 82043406Smckusick 82137586Smarc /* 82243406Smckusick * If the to-be-dup'd fd number is greater than the allowed number 82343406Smckusick * of file descriptors, or the fd to be dup'd has already been 82443406Smckusick * closed, reject. Note, check for new == old is necessary as 82543406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor 82643406Smckusick * as the new descriptor. 82737586Smarc */ 82847653Skarels fp = fdp->fd_ofiles[indx]; 82947653Skarels if ((u_int)dfd >= fdp->fd_nfiles || 83047653Skarels (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp) 83137586Smarc return (EBADF); 83240873Sbostic 83337586Smarc /* 83453826Spendry * There are two cases of interest here. 83553826Spendry * 83653826Spendry * For ENODEV simply dup (dfd) to file descriptor 83753826Spendry * (indx) and return. 83853826Spendry * 83953826Spendry * For ENXIO steal away the file structure from (dfd) and 84053826Spendry * store it in (indx). (dfd) is effectively closed by 84153826Spendry * this operation. 84253826Spendry * 84353826Spendry * Any other error code is just returned. 84437586Smarc */ 84553826Spendry switch (error) { 84653826Spendry case ENODEV: 84753826Spendry /* 84853826Spendry * Check that the mode the file is being opened for is a 84953826Spendry * subset of the mode of the existing descriptor. 85053826Spendry */ 85153826Spendry if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) 85253826Spendry return (EACCES); 85353826Spendry fdp->fd_ofiles[indx] = wfp; 85453826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 85553826Spendry wfp->f_count++; 85653826Spendry if (indx > fdp->fd_lastfile) 85753826Spendry fdp->fd_lastfile = indx; 85853826Spendry return (0); 85953826Spendry 86053826Spendry case ENXIO: 86153826Spendry /* 86253826Spendry * Steal away the file pointer from dfd, and stuff it into indx. 86353826Spendry */ 86453826Spendry fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd]; 86553826Spendry fdp->fd_ofiles[dfd] = NULL; 86653826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 86753826Spendry fdp->fd_ofileflags[dfd] = 0; 86853826Spendry /* 86953826Spendry * Complete the clean up of the filedesc structure by 87053826Spendry * recomputing the various hints. 87153826Spendry */ 87253826Spendry if (indx > fdp->fd_lastfile) 87353826Spendry fdp->fd_lastfile = indx; 87453826Spendry else 87553826Spendry while (fdp->fd_lastfile > 0 && 87653826Spendry fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 87753826Spendry fdp->fd_lastfile--; 87853826Spendry if (dfd < fdp->fd_freefile) 87953826Spendry fdp->fd_freefile = dfd; 88053826Spendry return (0); 88153826Spendry 88253826Spendry default: 88353826Spendry return (error); 88453826Spendry } 88553826Spendry /* NOTREACHED */ 88637586Smarc } 887