123367Smckusick /* 263170Sbostic * Copyright (c) 1982, 1986, 1989, 1991, 1993 363170Sbostic * The Regents of the University of California. All rights reserved. 465771Sbostic * (c) UNIX System Laboratories, Inc. 565771Sbostic * All or some portions of this file are derived from material licensed 665771Sbostic * to the University of California by American Telephone and Telegraph 765771Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 865771Sbostic * the permission of UNIX System Laboratories, Inc. 923367Smckusick * 1044431Sbostic * %sccs.include.redist.c% 1137728Smckusick * 12*67732Smckusick * @(#)kern_descrip.c 8.7 (Berkeley) 08/22/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 */ 35*67732Smckusick struct filelist filehead; /* head of list of open files */ 36*67732Smckusick 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 { 548*67732Smckusick register struct file *fp, *fq; 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); 56567007Smckusick bzero(fp, sizeof(struct file)); 566*67732Smckusick if (fq = p->p_fd->fd_ofiles[0]) { 567*67732Smckusick LIST_INSERT_AFTER(fq, fp, f_list); 568*67732Smckusick } else { 569*67732Smckusick LIST_INSERT_HEAD(&filehead, fp, f_list); 570*67732Smckusick } 57150129Smckusick p->p_fd->fd_ofiles[i] = fp; 57212748Ssam fp->f_count = 1; 57347540Skarels fp->f_cred = p->p_ucred; 57437728Smckusick crhold(fp->f_cred); 57537728Smckusick if (resultfp) 57637728Smckusick *resultfp = fp; 57737728Smckusick if (resultfd) 57837728Smckusick *resultfd = i; 57937728Smckusick return (0); 5807497Sroot } 58112748Ssam 5827497Sroot /* 58349981Smckusick * Free a file descriptor. 58449981Smckusick */ 58549981Smckusick ffree(fp) 58649981Smckusick register struct file *fp; 58749981Smckusick { 58849981Smckusick register struct file *fq; 58949981Smckusick 590*67732Smckusick LIST_REMOVE(fp, f_list); 59149981Smckusick crfree(fp->f_cred); 59249981Smckusick #ifdef DIAGNOSTIC 59349981Smckusick fp->f_count = 0; 59449981Smckusick #endif 59549981Smckusick nfiles--; 59649981Smckusick FREE(fp, M_FILE); 59749981Smckusick } 59849981Smckusick 59949981Smckusick /* 60047540Skarels * Copy a filedesc structure. 60145914Smckusick */ 60245914Smckusick struct filedesc * 60347540Skarels fdcopy(p) 60447540Skarels struct proc *p; 60545914Smckusick { 60647653Skarels register struct filedesc *newfdp, *fdp = p->p_fd; 60747653Skarels register struct file **fpp; 60845914Smckusick register int i; 60945914Smckusick 61047653Skarels MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0), 61147653Skarels M_FILEDESC, M_WAITOK); 61247653Skarels bcopy(fdp, newfdp, sizeof(struct filedesc)); 61345914Smckusick VREF(newfdp->fd_cdir); 61445914Smckusick if (newfdp->fd_rdir) 61545914Smckusick VREF(newfdp->fd_rdir); 61645914Smckusick newfdp->fd_refcnt = 1; 61747540Skarels 61847540Skarels /* 61947653Skarels * If the number of open files fits in the internal arrays 62047653Skarels * of the open file structure, use them, otherwise allocate 62147653Skarels * additional memory for the number of descriptors currently 62247653Skarels * in use. 62347540Skarels */ 62447653Skarels if (newfdp->fd_lastfile < NDFILE) { 62547653Skarels newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles; 62647653Skarels newfdp->fd_ofileflags = 62747653Skarels ((struct filedesc0 *) newfdp)->fd_dfileflags; 62847653Skarels i = NDFILE; 62947653Skarels } else { 63047653Skarels /* 63147653Skarels * Compute the smallest multiple of NDEXTENT needed 63247653Skarels * for the file descriptors currently in use, 63347653Skarels * allowing the table to shrink. 63447653Skarels */ 63547653Skarels i = newfdp->fd_nfiles; 63665547Smckusick while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2) 63747653Skarels i /= 2; 63847653Skarels MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE, 63947653Skarels M_FILEDESC, M_WAITOK); 64047653Skarels newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; 64147653Skarels } 64247540Skarels newfdp->fd_nfiles = i; 64347540Skarels bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **)); 64447540Skarels bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char)); 64547653Skarels fpp = newfdp->fd_ofiles; 64647653Skarels for (i = newfdp->fd_lastfile; i-- >= 0; fpp++) 64747653Skarels if (*fpp != NULL) 64847653Skarels (*fpp)->f_count++; 64945914Smckusick return (newfdp); 65045914Smckusick } 65145914Smckusick 65245914Smckusick /* 65345914Smckusick * Release a filedesc structure. 65445914Smckusick */ 65547653Skarels void 65647540Skarels fdfree(p) 65747540Skarels struct proc *p; 65845914Smckusick { 65947540Skarels register struct filedesc *fdp = p->p_fd; 66047653Skarels struct file **fpp; 66145914Smckusick register int i; 66245914Smckusick 66347540Skarels if (--fdp->fd_refcnt > 0) 66445914Smckusick return; 66547653Skarels fpp = fdp->fd_ofiles; 66647653Skarels for (i = fdp->fd_lastfile; i-- >= 0; fpp++) 66747653Skarels if (*fpp) 66847653Skarels (void) closef(*fpp, p); 66947653Skarels if (fdp->fd_nfiles > NDFILE) 67047653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 67145914Smckusick vrele(fdp->fd_cdir); 67245914Smckusick if (fdp->fd_rdir) 67345914Smckusick vrele(fdp->fd_rdir); 67447540Skarels FREE(fdp, M_FILEDESC); 67545914Smckusick } 67645914Smckusick 67745914Smckusick /* 6787497Sroot * Internal form of close. 67912748Ssam * Decrement reference count on file structure. 68052034Skarels * Note: p may be NULL when closing a file 68152034Skarels * that was being passed in a message. 6827497Sroot */ 68347540Skarels closef(fp, p) 6847497Sroot register struct file *fp; 68549981Smckusick register struct proc *p; 6867497Sroot { 68746200Smckusick struct vnode *vp; 68846200Smckusick struct flock lf; 68939354Smckusick int error; 6907497Sroot 6917422Sroot if (fp == NULL) 69239354Smckusick return (0); 69346200Smckusick /* 69446200Smckusick * POSIX record locking dictates that any close releases ALL 69546200Smckusick * locks owned by this process. This is handled by setting 69646200Smckusick * a flag in the unlock to free ONLY locks obeying POSIX 69746200Smckusick * semantics, and not to free BSD-style file locks. 69852034Skarels * If the descriptor was in a message, POSIX-style locks 69952034Skarels * aren't passed with the descriptor. 70046200Smckusick */ 70164593Sbostic if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) { 70246200Smckusick lf.l_whence = SEEK_SET; 70346200Smckusick lf.l_start = 0; 70446200Smckusick lf.l_len = 0; 70546200Smckusick lf.l_type = F_UNLCK; 70646200Smckusick vp = (struct vnode *)fp->f_data; 70748029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX); 70846200Smckusick } 70947540Skarels if (--fp->f_count > 0) 71039354Smckusick return (0); 71147540Skarels if (fp->f_count < 0) 71247540Skarels panic("closef: count < 0"); 71349951Smckusick if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) { 71449951Smckusick lf.l_whence = SEEK_SET; 71549951Smckusick lf.l_start = 0; 71649951Smckusick lf.l_len = 0; 71749951Smckusick lf.l_type = F_UNLCK; 71849951Smckusick vp = (struct vnode *)fp->f_data; 71948029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); 72049951Smckusick } 72167007Smckusick if (fp->f_ops) 72267007Smckusick error = (*fp->f_ops->fo_close)(fp, p); 72367007Smckusick else 72467007Smckusick error = 0; 72549981Smckusick ffree(fp); 72639354Smckusick return (error); 7277422Sroot } 72813044Ssam 72913044Ssam /* 73013044Ssam * Apply an advisory lock on a file descriptor. 73146200Smckusick * 73246200Smckusick * Just attempt to get a record lock of the requested type on 73346200Smckusick * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). 73413044Ssam */ 73554934Storek struct flock_args { 73654934Storek int fd; 73754934Storek int how; 73854934Storek }; 73942863Smckusick /* ARGSUSED */ 74042863Smckusick flock(p, uap, retval) 74142863Smckusick struct proc *p; 74254934Storek register struct flock_args *uap; 74342863Smckusick int *retval; 74442863Smckusick { 74545914Smckusick register struct filedesc *fdp = p->p_fd; 74613044Ssam register struct file *fp; 74746200Smckusick struct vnode *vp; 74846200Smckusick struct flock lf; 74913044Ssam 75047540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 75147653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 75244404Skarels return (EBADF); 75342863Smckusick if (fp->f_type != DTYPE_VNODE) 75444404Skarels return (EOPNOTSUPP); 75546200Smckusick vp = (struct vnode *)fp->f_data; 75646200Smckusick lf.l_whence = SEEK_SET; 75746200Smckusick lf.l_start = 0; 75846200Smckusick lf.l_len = 0; 75913101Ssam if (uap->how & LOCK_UN) { 76046200Smckusick lf.l_type = F_UNLCK; 76149951Smckusick fp->f_flag &= ~FHASLOCK; 76248029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK)); 76313044Ssam } 76417998Skarels if (uap->how & LOCK_EX) 76546200Smckusick lf.l_type = F_WRLCK; 76646200Smckusick else if (uap->how & LOCK_SH) 76746200Smckusick lf.l_type = F_RDLCK; 76846200Smckusick else 76946200Smckusick return (EBADF); 77049951Smckusick fp->f_flag |= FHASLOCK; 77146200Smckusick if (uap->how & LOCK_NB) 77248029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK)); 77348029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); 77413044Ssam } 77537586Smarc 77637586Smarc /* 77737586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 77837586Smarc * 77937586Smarc * Opening minor device N dup()s the file (if any) connected to file 78037586Smarc * descriptor N belonging to the calling process. Note that this driver 78137586Smarc * consists of only the ``open()'' routine, because all subsequent 78237586Smarc * references to this file will be direct to the other driver. 78337586Smarc */ 78437728Smckusick /* ARGSUSED */ 78552568Smckusick fdopen(dev, mode, type, p) 78637586Smarc dev_t dev; 78737728Smckusick int mode, type; 78852568Smckusick struct proc *p; 78937586Smarc { 79037586Smarc 79137586Smarc /* 79247540Skarels * XXX Kludge: set curproc->p_dupfd to contain the value of the 79343406Smckusick * the file descriptor being sought for duplication. The error 79443406Smckusick * return ensures that the vnode for this device will be released 79543406Smckusick * by vn_open. Open will detect this special error and take the 79643406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN 79743406Smckusick * will simply report the error. 79837586Smarc */ 79952568Smckusick p->p_dupfd = minor(dev); 80043406Smckusick return (ENODEV); 80143406Smckusick } 80240873Sbostic 80343406Smckusick /* 80443406Smckusick * Duplicate the specified descriptor to a free descriptor. 80543406Smckusick */ 80653826Spendry dupfdopen(fdp, indx, dfd, mode, error) 80745914Smckusick register struct filedesc *fdp; 80843406Smckusick register int indx, dfd; 80943406Smckusick int mode; 81053826Spendry int error; 81143406Smckusick { 81243406Smckusick register struct file *wfp; 81343406Smckusick struct file *fp; 81443406Smckusick 81537586Smarc /* 81643406Smckusick * If the to-be-dup'd fd number is greater than the allowed number 81743406Smckusick * of file descriptors, or the fd to be dup'd has already been 81843406Smckusick * closed, reject. Note, check for new == old is necessary as 81943406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor 82043406Smckusick * as the new descriptor. 82137586Smarc */ 82247653Skarels fp = fdp->fd_ofiles[indx]; 82347653Skarels if ((u_int)dfd >= fdp->fd_nfiles || 82447653Skarels (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp) 82537586Smarc return (EBADF); 82640873Sbostic 82737586Smarc /* 82853826Spendry * There are two cases of interest here. 82953826Spendry * 83053826Spendry * For ENODEV simply dup (dfd) to file descriptor 83153826Spendry * (indx) and return. 83253826Spendry * 83353826Spendry * For ENXIO steal away the file structure from (dfd) and 83453826Spendry * store it in (indx). (dfd) is effectively closed by 83553826Spendry * this operation. 83653826Spendry * 83753826Spendry * Any other error code is just returned. 83837586Smarc */ 83953826Spendry switch (error) { 84053826Spendry case ENODEV: 84153826Spendry /* 84253826Spendry * Check that the mode the file is being opened for is a 84353826Spendry * subset of the mode of the existing descriptor. 84453826Spendry */ 84553826Spendry if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) 84653826Spendry return (EACCES); 84753826Spendry fdp->fd_ofiles[indx] = wfp; 84853826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 84953826Spendry wfp->f_count++; 85053826Spendry if (indx > fdp->fd_lastfile) 85153826Spendry fdp->fd_lastfile = indx; 85253826Spendry return (0); 85353826Spendry 85453826Spendry case ENXIO: 85553826Spendry /* 85653826Spendry * Steal away the file pointer from dfd, and stuff it into indx. 85753826Spendry */ 85853826Spendry fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd]; 85953826Spendry fdp->fd_ofiles[dfd] = NULL; 86053826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 86153826Spendry fdp->fd_ofileflags[dfd] = 0; 86253826Spendry /* 86353826Spendry * Complete the clean up of the filedesc structure by 86453826Spendry * recomputing the various hints. 86553826Spendry */ 86653826Spendry if (indx > fdp->fd_lastfile) 86753826Spendry fdp->fd_lastfile = indx; 86853826Spendry else 86953826Spendry while (fdp->fd_lastfile > 0 && 87053826Spendry fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 87153826Spendry fdp->fd_lastfile--; 87253826Spendry if (dfd < fdp->fd_freefile) 87353826Spendry fdp->fd_freefile = dfd; 87453826Spendry return (0); 87553826Spendry 87653826Spendry default: 87753826Spendry return (error); 87853826Spendry } 87953826Spendry /* NOTREACHED */ 88037586Smarc } 881