123367Smckusick /* 263170Sbostic * Copyright (c) 1982, 1986, 1989, 1991, 1993 363170Sbostic * The Regents of the University of California. All rights reserved. 423367Smckusick * 544431Sbostic * %sccs.include.redist.c% 637728Smckusick * 7*65547Smckusick * @(#)kern_descrip.c 8.4 (Berkeley) 01/06/94 823367Smckusick */ 97422Sroot 1056517Sbostic #include <sys/param.h> 1156517Sbostic #include <sys/systm.h> 1256517Sbostic #include <sys/filedesc.h> 1356517Sbostic #include <sys/kernel.h> 1456517Sbostic #include <sys/vnode.h> 1556517Sbostic #include <sys/proc.h> 1656517Sbostic #include <sys/file.h> 1756517Sbostic #include <sys/socket.h> 1856517Sbostic #include <sys/socketvar.h> 1956517Sbostic #include <sys/stat.h> 2056517Sbostic #include <sys/ioctl.h> 2156517Sbostic #include <sys/fcntl.h> 2256517Sbostic #include <sys/malloc.h> 2356517Sbostic #include <sys/syslog.h> 2460413Smckusick #include <sys/unistd.h> 2556517Sbostic #include <sys/resourcevar.h> 267497Sroot 277422Sroot /* 287497Sroot * Descriptor management. 297422Sroot */ 3049981Smckusick struct file *filehead; /* head of list of open files */ 3149981Smckusick int nfiles; /* actual number of open files */ 327497Sroot 337497Sroot /* 347497Sroot * System calls on descriptors. 357497Sroot */ 3654934Storek struct getdtablesize_args { 3754934Storek int dummy; 3854934Storek }; 3942863Smckusick /* ARGSUSED */ 4042863Smckusick getdtablesize(p, uap, retval) 4142863Smckusick struct proc *p; 4254934Storek struct getdtablesize_args *uap; 4342863Smckusick int *retval; 447497Sroot { 457497Sroot 4658775Smckusick *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); 4744404Skarels return (0); 487497Sroot } 497497Sroot 5042863Smckusick /* 5142863Smckusick * Duplicate a file descriptor. 5242863Smckusick */ 5354934Storek struct dup_args { 5458775Smckusick u_int fd; 5554934Storek }; 5642863Smckusick /* ARGSUSED */ 5742863Smckusick dup(p, uap, retval) 5842863Smckusick struct proc *p; 5954934Storek struct dup_args *uap; 6042863Smckusick int *retval; 617422Sroot { 6258775Smckusick register struct filedesc *fdp; 6358775Smckusick u_int old; 6458775Smckusick int new, error; 657497Sroot 6658775Smckusick old = uap->fd; 6742863Smckusick /* 6842863Smckusick * XXX Compatibility 6942863Smckusick */ 7058775Smckusick if (old &~ 077) { uap->fd &= 077; return (dup2(p, uap, retval)); } 717497Sroot 7258775Smckusick fdp = p->p_fd; 7358775Smckusick if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL) 7444404Skarels return (EBADF); 7558775Smckusick if (error = fdalloc(p, 0, &new)) 7644404Skarels return (error); 7758775Smckusick return (finishdup(fdp, (int)old, new, retval)); 787497Sroot } 797497Sroot 8042863Smckusick /* 8142863Smckusick * Duplicate a file descriptor to a particular value. 8242863Smckusick */ 8354934Storek struct dup2_args { 8454934Storek u_int from; 8554934Storek u_int to; 8654934Storek }; 8742863Smckusick /* ARGSUSED */ 8842863Smckusick dup2(p, uap, retval) 8942863Smckusick struct proc *p; 9054934Storek struct dup2_args *uap; 9142863Smckusick int *retval; 927497Sroot { 9345914Smckusick register struct filedesc *fdp = p->p_fd; 9447653Skarels register u_int old = uap->from, new = uap->to; 9545914Smckusick int i, error; 967422Sroot 9747653Skarels if (old >= fdp->fd_nfiles || 9858775Smckusick fdp->fd_ofiles[old] == NULL || 9958656Smckusick new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || 10058775Smckusick new >= maxfiles) 10144404Skarels return (EBADF); 10258775Smckusick if (old == new) { 10358775Smckusick *retval = new; 10444404Skarels return (0); 10558775Smckusick } 10647653Skarels if (new >= fdp->fd_nfiles) { 10747653Skarels if (error = fdalloc(p, new, &i)) 10845914Smckusick return (error); 10947653Skarels if (new != i) 11047540Skarels panic("dup2: fdalloc"); 11147653Skarels } else if (fdp->fd_ofiles[new]) { 11247653Skarels if (fdp->fd_ofileflags[new] & UF_MAPPED) 11347653Skarels (void) munmapfd(p, new); 11447653Skarels /* 11547653Skarels * dup2() must succeed even if the close has an error. 11647653Skarels */ 11747653Skarels (void) closef(fdp->fd_ofiles[new], p); 1187422Sroot } 11958775Smckusick return (finishdup(fdp, (int)old, (int)new, retval)); 1207696Ssam } 1217696Ssam 12212748Ssam /* 12312748Ssam * The file control system call. 12412748Ssam */ 12554934Storek struct fcntl_args { 12654934Storek int fd; 12754934Storek int cmd; 12854934Storek int arg; 12954934Storek }; 13042863Smckusick /* ARGSUSED */ 13142863Smckusick fcntl(p, uap, retval) 13242863Smckusick struct proc *p; 13354934Storek register struct fcntl_args *uap; 13442863Smckusick int *retval; 13542863Smckusick { 13645914Smckusick register struct filedesc *fdp = p->p_fd; 13742863Smckusick register struct file *fp; 13812748Ssam register char *pop; 13946200Smckusick struct vnode *vp; 14048029Smckusick int i, tmp, error, flg = F_POSIX; 14146200Smckusick struct flock fl; 14258775Smckusick u_int newmin; 1437497Sroot 14447540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 14547653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 14644404Skarels return (EBADF); 14747653Skarels pop = &fdp->fd_ofileflags[uap->fd]; 14858775Smckusick switch (uap->cmd) { 14958775Smckusick 15015076Skarels case F_DUPFD: 15158775Smckusick newmin = uap->arg; 15258775Smckusick if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || 15358775Smckusick newmin >= maxfiles) 15444404Skarels return (EINVAL); 15558775Smckusick if (error = fdalloc(p, newmin, &i)) 15644404Skarels return (error); 15758775Smckusick return (finishdup(fdp, uap->fd, i, retval)); 1587497Sroot 15915076Skarels case F_GETFD: 16042863Smckusick *retval = *pop & 1; 16144404Skarels return (0); 1627422Sroot 16315076Skarels case F_SETFD: 16412748Ssam *pop = (*pop &~ 1) | (uap->arg & 1); 16544404Skarels return (0); 1668145Sroot 16715076Skarels case F_GETFL: 16846495Skarels *retval = OFLAGS(fp->f_flag); 16944404Skarels return (0); 1708145Sroot 17115076Skarels case F_SETFL: 17246495Skarels fp->f_flag &= ~FCNTLFLAGS; 17346495Skarels fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS; 17449940Smckusick tmp = fp->f_flag & FNONBLOCK; 17548029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 17648029Smckusick if (error) 17744404Skarels return (error); 17849940Smckusick tmp = fp->f_flag & FASYNC; 17948029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); 18048029Smckusick if (!error) 18148029Smckusick return (0); 18249940Smckusick fp->f_flag &= ~FNONBLOCK; 18348029Smckusick tmp = 0; 18448029Smckusick (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 18544404Skarels return (error); 1867422Sroot 18715076Skarels case F_GETOWN: 18848029Smckusick if (fp->f_type == DTYPE_SOCKET) { 18948029Smckusick *retval = ((struct socket *)fp->f_data)->so_pgid; 19048029Smckusick return (0); 19148029Smckusick } 19248029Smckusick error = (*fp->f_ops->fo_ioctl) 19348029Smckusick (fp, (int)TIOCGPGRP, (caddr_t)retval, p); 19448029Smckusick *retval = -*retval; 19548029Smckusick return (error); 1967422Sroot 19715076Skarels case F_SETOWN: 19848029Smckusick if (fp->f_type == DTYPE_SOCKET) { 19948029Smckusick ((struct socket *)fp->f_data)->so_pgid = uap->arg; 20048029Smckusick return (0); 20148029Smckusick } 20248029Smckusick if (uap->arg <= 0) { 20348029Smckusick uap->arg = -uap->arg; 20448029Smckusick } else { 20548029Smckusick struct proc *p1 = pfind(uap->arg); 20648029Smckusick if (p1 == 0) 20748029Smckusick return (ESRCH); 20848029Smckusick uap->arg = p1->p_pgrp->pg_id; 20948029Smckusick } 21048029Smckusick return ((*fp->f_ops->fo_ioctl) 21148029Smckusick (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p)); 2128115Sroot 21346200Smckusick case F_SETLKW: 21448029Smckusick flg |= F_WAIT; 21546200Smckusick /* Fall into F_SETLK */ 21646200Smckusick 21746200Smckusick case F_SETLK: 21846200Smckusick if (fp->f_type != DTYPE_VNODE) 21946200Smckusick return (EBADF); 22046200Smckusick vp = (struct vnode *)fp->f_data; 22146200Smckusick /* Copy in the lock structure */ 22246200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 22346200Smckusick if (error) 22446200Smckusick return (error); 22546200Smckusick if (fl.l_whence == SEEK_CUR) 22646200Smckusick fl.l_start += fp->f_offset; 22746200Smckusick switch (fl.l_type) { 22846200Smckusick 22946200Smckusick case F_RDLCK: 23046200Smckusick if ((fp->f_flag & FREAD) == 0) 23146200Smckusick return (EBADF); 23264593Sbostic p->p_flag |= P_ADVLOCK; 23348029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 23446200Smckusick 23546200Smckusick case F_WRLCK: 23646200Smckusick if ((fp->f_flag & FWRITE) == 0) 23746200Smckusick return (EBADF); 23864593Sbostic p->p_flag |= P_ADVLOCK; 23948029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 24046200Smckusick 24146200Smckusick case F_UNLCK: 24248029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl, 24348029Smckusick F_POSIX)); 24446200Smckusick 24546200Smckusick default: 24646200Smckusick return (EINVAL); 24746200Smckusick } 24846200Smckusick 24946200Smckusick case F_GETLK: 25046200Smckusick if (fp->f_type != DTYPE_VNODE) 25146200Smckusick return (EBADF); 25246200Smckusick vp = (struct vnode *)fp->f_data; 25346200Smckusick /* Copy in the lock structure */ 25446200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 25546200Smckusick if (error) 25646200Smckusick return (error); 25746765Smckusick if (fl.l_whence == SEEK_CUR) 25846765Smckusick fl.l_start += fp->f_offset; 25948029Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX)) 26046200Smckusick return (error); 26146200Smckusick return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl))); 26246200Smckusick 26312748Ssam default: 26444404Skarels return (EINVAL); 2657422Sroot } 26642863Smckusick /* NOTREACHED */ 2677422Sroot } 2687422Sroot 26942863Smckusick /* 27058775Smckusick * Common code for dup, dup2, and fcntl(F_DUPFD). 27158775Smckusick */ 27258775Smckusick int 27358775Smckusick finishdup(fdp, old, new, retval) 27458775Smckusick register struct filedesc *fdp; 27558775Smckusick register int old, new, *retval; 27658775Smckusick { 27758775Smckusick register struct file *fp; 27858775Smckusick 27958775Smckusick fp = fdp->fd_ofiles[old]; 28058775Smckusick fdp->fd_ofiles[new] = fp; 28158775Smckusick fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; 28258775Smckusick fp->f_count++; 28358775Smckusick if (new > fdp->fd_lastfile) 28458775Smckusick fdp->fd_lastfile = new; 28558775Smckusick *retval = new; 28658775Smckusick return (0); 28758775Smckusick } 28858775Smckusick 28958775Smckusick /* 29042863Smckusick * Close a file descriptor. 29142863Smckusick */ 29254934Storek struct close_args { 29354934Storek int fd; 29454934Storek }; 29542863Smckusick /* ARGSUSED */ 29642863Smckusick close(p, uap, retval) 29742863Smckusick struct proc *p; 29854934Storek struct close_args *uap; 29942863Smckusick int *retval; 3008029Sroot { 30145914Smckusick register struct filedesc *fdp = p->p_fd; 30212748Ssam register struct file *fp; 30347540Skarels register int fd = uap->fd; 30413044Ssam register u_char *pf; 3058029Sroot 30647540Skarels if ((unsigned)fd >= fdp->fd_nfiles || 30747653Skarels (fp = fdp->fd_ofiles[fd]) == NULL) 30844404Skarels return (EBADF); 30947653Skarels pf = (u_char *)&fdp->fd_ofileflags[fd]; 31013044Ssam if (*pf & UF_MAPPED) 31147540Skarels (void) munmapfd(p, fd); 31247653Skarels fdp->fd_ofiles[fd] = NULL; 31347653Skarels while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 31445914Smckusick fdp->fd_lastfile--; 31547540Skarels if (fd < fdp->fd_freefile) 31647540Skarels fdp->fd_freefile = fd; 31715550Skarels *pf = 0; 31847540Skarels return (closef(fp, p)); 3198029Sroot } 3208029Sroot 32154346Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 32242863Smckusick /* 32342863Smckusick * Return status information about a file descriptor. 32442863Smckusick */ 32554934Storek struct ofstat_args { 32654934Storek int fd; 32754934Storek struct ostat *sb; 32854934Storek }; 32942863Smckusick /* ARGSUSED */ 33053758Smckusick ofstat(p, uap, retval) 33142863Smckusick struct proc *p; 33254934Storek register struct ofstat_args *uap; 33353466Smckusick int *retval; 33453466Smckusick { 33553466Smckusick register struct filedesc *fdp = p->p_fd; 33653466Smckusick register struct file *fp; 33753466Smckusick struct stat ub; 33853466Smckusick struct ostat oub; 33953466Smckusick int error; 34053466Smckusick 34153466Smckusick if ((unsigned)uap->fd >= fdp->fd_nfiles || 34253466Smckusick (fp = fdp->fd_ofiles[uap->fd]) == NULL) 34353466Smckusick return (EBADF); 34453466Smckusick switch (fp->f_type) { 34553466Smckusick 34653466Smckusick case DTYPE_VNODE: 34753466Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p); 34853466Smckusick break; 34953466Smckusick 35053466Smckusick case DTYPE_SOCKET: 35153466Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 35253466Smckusick break; 35353466Smckusick 35453466Smckusick default: 35554346Smckusick panic("ofstat"); 35653466Smckusick /*NOTREACHED*/ 35753466Smckusick } 35853466Smckusick cvtstat(&ub, &oub); 35953466Smckusick if (error == 0) 36053466Smckusick error = copyout((caddr_t)&oub, (caddr_t)uap->sb, sizeof (oub)); 36153466Smckusick return (error); 36253466Smckusick } 36354346Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */ 36453466Smckusick 36553466Smckusick /* 36653466Smckusick * Return status information about a file descriptor. 36753466Smckusick */ 36854934Storek struct fstat_args { 36954934Storek int fd; 37054934Storek struct stat *sb; 37154934Storek }; 37253466Smckusick /* ARGSUSED */ 37353758Smckusick fstat(p, uap, retval) 37453466Smckusick struct proc *p; 37554934Storek register struct fstat_args *uap; 37642863Smckusick int *retval; 37713044Ssam { 37845914Smckusick register struct filedesc *fdp = p->p_fd; 37913044Ssam register struct file *fp; 38013044Ssam struct stat ub; 38142863Smckusick int error; 38213044Ssam 38347540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 38447653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 38544404Skarels return (EBADF); 38613044Ssam switch (fp->f_type) { 38713044Ssam 38837728Smckusick case DTYPE_VNODE: 38948029Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p); 39013044Ssam break; 39113044Ssam 39213044Ssam case DTYPE_SOCKET: 39342863Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 39413044Ssam break; 39513044Ssam 39613044Ssam default: 39713044Ssam panic("fstat"); 39813044Ssam /*NOTREACHED*/ 39913044Ssam } 40042863Smckusick if (error == 0) 40142863Smckusick error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); 40244404Skarels return (error); 40313044Ssam } 40413044Ssam 4057422Sroot /* 40660413Smckusick * Return pathconf information about a file descriptor. 40760413Smckusick */ 40860413Smckusick struct fpathconf_args { 40960413Smckusick int fd; 41060413Smckusick int name; 41160413Smckusick }; 41260413Smckusick /* ARGSUSED */ 41360413Smckusick fpathconf(p, uap, retval) 41460413Smckusick struct proc *p; 41560413Smckusick register struct fpathconf_args *uap; 41660413Smckusick int *retval; 41760413Smckusick { 41860413Smckusick struct filedesc *fdp = p->p_fd; 41960413Smckusick struct file *fp; 42060413Smckusick struct vnode *vp; 42160413Smckusick 42260413Smckusick if ((unsigned)uap->fd >= fdp->fd_nfiles || 42360413Smckusick (fp = fdp->fd_ofiles[uap->fd]) == NULL) 42460413Smckusick return (EBADF); 42560413Smckusick switch (fp->f_type) { 42660413Smckusick 42760413Smckusick case DTYPE_SOCKET: 42860413Smckusick if (uap->name != _PC_PIPE_BUF) 42960413Smckusick return (EINVAL); 43060413Smckusick *retval = PIPE_BUF; 43160413Smckusick return (0); 43260413Smckusick 43360413Smckusick case DTYPE_VNODE: 43460413Smckusick vp = (struct vnode *)fp->f_data; 43560413Smckusick return (VOP_PATHCONF(vp, uap->name, retval)); 43660413Smckusick 43760413Smckusick default: 43860413Smckusick panic("fpathconf"); 43960413Smckusick } 44060413Smckusick /*NOTREACHED*/ 44160413Smckusick } 44260413Smckusick 44360413Smckusick /* 44447540Skarels * Allocate a file descriptor for the process. 4457422Sroot */ 44647540Skarels int fdexpand; 44745914Smckusick 44847540Skarels fdalloc(p, want, result) 44947540Skarels struct proc *p; 45047540Skarels int want; 45137728Smckusick int *result; 4527422Sroot { 45347540Skarels register struct filedesc *fdp = p->p_fd; 45447540Skarels register int i; 45547540Skarels int lim, last, nfiles; 45645914Smckusick struct file **newofile; 45745914Smckusick char *newofileflags; 4587497Sroot 45947540Skarels /* 46047540Skarels * Search for a free descriptor starting at the higher 46147540Skarels * of want or fd_freefile. If that fails, consider 46247540Skarels * expanding the ofile array. 46347540Skarels */ 46458775Smckusick lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); 46545914Smckusick for (;;) { 46647540Skarels last = min(fdp->fd_nfiles, lim); 46747540Skarels if ((i = want) < fdp->fd_freefile) 46847540Skarels i = fdp->fd_freefile; 46947540Skarels for (; i < last; i++) { 47047653Skarels if (fdp->fd_ofiles[i] == NULL) { 47147653Skarels fdp->fd_ofileflags[i] = 0; 47247540Skarels if (i > fdp->fd_lastfile) 47347540Skarels fdp->fd_lastfile = i; 47447653Skarels if (want <= fdp->fd_freefile) 47547540Skarels fdp->fd_freefile = i; 47647540Skarels *result = i; 47745914Smckusick return (0); 47845914Smckusick } 4797497Sroot } 48047540Skarels 48147540Skarels /* 48247540Skarels * No space in current array. Expand? 48347540Skarels */ 48447540Skarels if (fdp->fd_nfiles >= lim) 48545914Smckusick return (EMFILE); 48647653Skarels if (fdp->fd_nfiles < NDEXTENT) 48747653Skarels nfiles = NDEXTENT; 48847653Skarels else 48947653Skarels nfiles = 2 * fdp->fd_nfiles; 49047540Skarels MALLOC(newofile, struct file **, nfiles * OFILESIZE, 49147540Skarels M_FILEDESC, M_WAITOK); 49247540Skarels newofileflags = (char *) &newofile[nfiles]; 49347540Skarels /* 49447540Skarels * Copy the existing ofile and ofileflags arrays 49547540Skarels * and zero the new portion of each array. 49647540Skarels */ 49747540Skarels bcopy(fdp->fd_ofiles, newofile, 49847540Skarels (i = sizeof(struct file *) * fdp->fd_nfiles)); 49947540Skarels bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i); 50047540Skarels bcopy(fdp->fd_ofileflags, newofileflags, 50147540Skarels (i = sizeof(char) * fdp->fd_nfiles)); 50247540Skarels bzero(newofileflags + i, nfiles * sizeof(char) - i); 50347653Skarels if (fdp->fd_nfiles > NDFILE) 50447653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 50547540Skarels fdp->fd_ofiles = newofile; 50647540Skarels fdp->fd_ofileflags = newofileflags; 50747540Skarels fdp->fd_nfiles = nfiles; 50847540Skarels fdexpand++; 50939733Smckusick } 5107497Sroot } 5117497Sroot 51242863Smckusick /* 51347653Skarels * Check to see whether n user file descriptors 51447653Skarels * are available to the process p. 51542863Smckusick */ 51647540Skarels fdavail(p, n) 51747540Skarels struct proc *p; 51847540Skarels register int n; 51912748Ssam { 52047540Skarels register struct filedesc *fdp = p->p_fd; 52147653Skarels register struct file **fpp; 52258775Smckusick register int i, lim; 52312748Ssam 52458775Smckusick lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); 52558775Smckusick if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0) 52647540Skarels return (1); 52747653Skarels fpp = &fdp->fd_ofiles[fdp->fd_freefile]; 52847653Skarels for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++) 52947653Skarels if (*fpp == NULL && --n <= 0) 53047540Skarels return (1); 53147540Skarels return (0); 53212748Ssam } 53312748Ssam 5347497Sroot /* 53547540Skarels * Create a new open file structure and allocate 53647540Skarels * a file decriptor for the process that refers to it. 5377497Sroot */ 53845914Smckusick falloc(p, resultfp, resultfd) 53945914Smckusick register struct proc *p; 54037728Smckusick struct file **resultfp; 54137728Smckusick int *resultfd; 5427497Sroot { 54349981Smckusick register struct file *fp, *fq, **fpp; 54437728Smckusick int error, i; 5457422Sroot 54647540Skarels if (error = fdalloc(p, 0, &i)) 54737728Smckusick return (error); 54849981Smckusick if (nfiles >= maxfiles) { 54949981Smckusick tablefull("file"); 55049981Smckusick return (ENFILE); 55149981Smckusick } 55249981Smckusick /* 55349981Smckusick * Allocate a new file descriptor. 55449981Smckusick * If the process has file descriptor zero open, add to the list 55549981Smckusick * of open files at that point, otherwise put it at the front of 55649981Smckusick * the list of open files. 55749981Smckusick */ 55849981Smckusick nfiles++; 55949981Smckusick MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK); 56049981Smckusick if (fq = p->p_fd->fd_ofiles[0]) 56149981Smckusick fpp = &fq->f_filef; 56249981Smckusick else 56349981Smckusick fpp = &filehead; 56450129Smckusick p->p_fd->fd_ofiles[i] = fp; 56549981Smckusick if (fq = *fpp) 56649981Smckusick fq->f_fileb = &fp->f_filef; 56749981Smckusick fp->f_filef = fq; 56849981Smckusick fp->f_fileb = fpp; 56949981Smckusick *fpp = fp; 57012748Ssam fp->f_count = 1; 57149981Smckusick fp->f_msgcount = 0; 5727497Sroot fp->f_offset = 0; 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 59049981Smckusick if (fq = fp->f_filef) 59149981Smckusick fq->f_fileb = fp->f_fileb; 59249981Smckusick *fp->f_fileb = fq; 59349981Smckusick crfree(fp->f_cred); 59449981Smckusick #ifdef DIAGNOSTIC 59549981Smckusick fp->f_filef = NULL; 59649981Smckusick fp->f_fileb = NULL; 59749981Smckusick fp->f_count = 0; 59849981Smckusick #endif 59949981Smckusick nfiles--; 60049981Smckusick FREE(fp, M_FILE); 60149981Smckusick } 60249981Smckusick 60349981Smckusick /* 60447540Skarels * Copy a filedesc structure. 60545914Smckusick */ 60645914Smckusick struct filedesc * 60747540Skarels fdcopy(p) 60847540Skarels struct proc *p; 60945914Smckusick { 61047653Skarels register struct filedesc *newfdp, *fdp = p->p_fd; 61147653Skarels register struct file **fpp; 61245914Smckusick register int i; 61345914Smckusick 61447653Skarels MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0), 61547653Skarels M_FILEDESC, M_WAITOK); 61647653Skarels bcopy(fdp, newfdp, sizeof(struct filedesc)); 61745914Smckusick VREF(newfdp->fd_cdir); 61845914Smckusick if (newfdp->fd_rdir) 61945914Smckusick VREF(newfdp->fd_rdir); 62045914Smckusick newfdp->fd_refcnt = 1; 62147540Skarels 62247540Skarels /* 62347653Skarels * If the number of open files fits in the internal arrays 62447653Skarels * of the open file structure, use them, otherwise allocate 62547653Skarels * additional memory for the number of descriptors currently 62647653Skarels * in use. 62747540Skarels */ 62847653Skarels if (newfdp->fd_lastfile < NDFILE) { 62947653Skarels newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles; 63047653Skarels newfdp->fd_ofileflags = 63147653Skarels ((struct filedesc0 *) newfdp)->fd_dfileflags; 63247653Skarels i = NDFILE; 63347653Skarels } else { 63447653Skarels /* 63547653Skarels * Compute the smallest multiple of NDEXTENT needed 63647653Skarels * for the file descriptors currently in use, 63747653Skarels * allowing the table to shrink. 63847653Skarels */ 63947653Skarels i = newfdp->fd_nfiles; 640*65547Smckusick while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2) 64147653Skarels i /= 2; 64247653Skarels MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE, 64347653Skarels M_FILEDESC, M_WAITOK); 64447653Skarels newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; 64547653Skarels } 64647540Skarels newfdp->fd_nfiles = i; 64747540Skarels bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **)); 64847540Skarels bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char)); 64947653Skarels fpp = newfdp->fd_ofiles; 65047653Skarels for (i = newfdp->fd_lastfile; i-- >= 0; fpp++) 65147653Skarels if (*fpp != NULL) 65247653Skarels (*fpp)->f_count++; 65345914Smckusick return (newfdp); 65445914Smckusick } 65545914Smckusick 65645914Smckusick /* 65745914Smckusick * Release a filedesc structure. 65845914Smckusick */ 65947653Skarels void 66047540Skarels fdfree(p) 66147540Skarels struct proc *p; 66245914Smckusick { 66347540Skarels register struct filedesc *fdp = p->p_fd; 66447653Skarels struct file **fpp; 66545914Smckusick register int i; 66645914Smckusick 66747540Skarels if (--fdp->fd_refcnt > 0) 66845914Smckusick return; 66947653Skarels fpp = fdp->fd_ofiles; 67047653Skarels for (i = fdp->fd_lastfile; i-- >= 0; fpp++) 67147653Skarels if (*fpp) 67247653Skarels (void) closef(*fpp, p); 67347653Skarels if (fdp->fd_nfiles > NDFILE) 67447653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 67545914Smckusick vrele(fdp->fd_cdir); 67645914Smckusick if (fdp->fd_rdir) 67745914Smckusick vrele(fdp->fd_rdir); 67847540Skarels FREE(fdp, M_FILEDESC); 67945914Smckusick } 68045914Smckusick 68145914Smckusick /* 6827497Sroot * Internal form of close. 68312748Ssam * Decrement reference count on file structure. 68452034Skarels * Note: p may be NULL when closing a file 68552034Skarels * that was being passed in a message. 6867497Sroot */ 68747540Skarels closef(fp, p) 6887497Sroot register struct file *fp; 68949981Smckusick register struct proc *p; 6907497Sroot { 69146200Smckusick struct vnode *vp; 69246200Smckusick struct flock lf; 69339354Smckusick int error; 6947497Sroot 6957422Sroot if (fp == NULL) 69639354Smckusick return (0); 69746200Smckusick /* 69846200Smckusick * POSIX record locking dictates that any close releases ALL 69946200Smckusick * locks owned by this process. This is handled by setting 70046200Smckusick * a flag in the unlock to free ONLY locks obeying POSIX 70146200Smckusick * semantics, and not to free BSD-style file locks. 70252034Skarels * If the descriptor was in a message, POSIX-style locks 70352034Skarels * aren't passed with the descriptor. 70446200Smckusick */ 70564593Sbostic if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) { 70646200Smckusick lf.l_whence = SEEK_SET; 70746200Smckusick lf.l_start = 0; 70846200Smckusick lf.l_len = 0; 70946200Smckusick lf.l_type = F_UNLCK; 71046200Smckusick vp = (struct vnode *)fp->f_data; 71148029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX); 71246200Smckusick } 71347540Skarels if (--fp->f_count > 0) 71439354Smckusick return (0); 71547540Skarels if (fp->f_count < 0) 71647540Skarels panic("closef: count < 0"); 71749951Smckusick if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) { 71849951Smckusick lf.l_whence = SEEK_SET; 71949951Smckusick lf.l_start = 0; 72049951Smckusick lf.l_len = 0; 72149951Smckusick lf.l_type = F_UNLCK; 72249951Smckusick vp = (struct vnode *)fp->f_data; 72348029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); 72449951Smckusick } 72548029Smckusick error = (*fp->f_ops->fo_close)(fp, p); 72649981Smckusick ffree(fp); 72739354Smckusick return (error); 7287422Sroot } 72913044Ssam 73013044Ssam /* 73113044Ssam * Apply an advisory lock on a file descriptor. 73246200Smckusick * 73346200Smckusick * Just attempt to get a record lock of the requested type on 73446200Smckusick * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). 73513044Ssam */ 73654934Storek struct flock_args { 73754934Storek int fd; 73854934Storek int how; 73954934Storek }; 74042863Smckusick /* ARGSUSED */ 74142863Smckusick flock(p, uap, retval) 74242863Smckusick struct proc *p; 74354934Storek register struct flock_args *uap; 74442863Smckusick int *retval; 74542863Smckusick { 74645914Smckusick register struct filedesc *fdp = p->p_fd; 74713044Ssam register struct file *fp; 74846200Smckusick struct vnode *vp; 74946200Smckusick struct flock lf; 75013044Ssam 75147540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 75247653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 75344404Skarels return (EBADF); 75442863Smckusick if (fp->f_type != DTYPE_VNODE) 75544404Skarels return (EOPNOTSUPP); 75646200Smckusick vp = (struct vnode *)fp->f_data; 75746200Smckusick lf.l_whence = SEEK_SET; 75846200Smckusick lf.l_start = 0; 75946200Smckusick lf.l_len = 0; 76013101Ssam if (uap->how & LOCK_UN) { 76146200Smckusick lf.l_type = F_UNLCK; 76249951Smckusick fp->f_flag &= ~FHASLOCK; 76348029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK)); 76413044Ssam } 76517998Skarels if (uap->how & LOCK_EX) 76646200Smckusick lf.l_type = F_WRLCK; 76746200Smckusick else if (uap->how & LOCK_SH) 76846200Smckusick lf.l_type = F_RDLCK; 76946200Smckusick else 77046200Smckusick return (EBADF); 77149951Smckusick fp->f_flag |= FHASLOCK; 77246200Smckusick if (uap->how & LOCK_NB) 77348029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK)); 77448029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); 77513044Ssam } 77637586Smarc 77737586Smarc /* 77837586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 77937586Smarc * 78037586Smarc * Opening minor device N dup()s the file (if any) connected to file 78137586Smarc * descriptor N belonging to the calling process. Note that this driver 78237586Smarc * consists of only the ``open()'' routine, because all subsequent 78337586Smarc * references to this file will be direct to the other driver. 78437586Smarc */ 78537728Smckusick /* ARGSUSED */ 78652568Smckusick fdopen(dev, mode, type, p) 78737586Smarc dev_t dev; 78837728Smckusick int mode, type; 78952568Smckusick struct proc *p; 79037586Smarc { 79137586Smarc 79237586Smarc /* 79347540Skarels * XXX Kludge: set curproc->p_dupfd to contain the value of the 79443406Smckusick * the file descriptor being sought for duplication. The error 79543406Smckusick * return ensures that the vnode for this device will be released 79643406Smckusick * by vn_open. Open will detect this special error and take the 79743406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN 79843406Smckusick * will simply report the error. 79937586Smarc */ 80052568Smckusick p->p_dupfd = minor(dev); 80143406Smckusick return (ENODEV); 80243406Smckusick } 80340873Sbostic 80443406Smckusick /* 80543406Smckusick * Duplicate the specified descriptor to a free descriptor. 80643406Smckusick */ 80753826Spendry dupfdopen(fdp, indx, dfd, mode, error) 80845914Smckusick register struct filedesc *fdp; 80943406Smckusick register int indx, dfd; 81043406Smckusick int mode; 81153826Spendry int error; 81243406Smckusick { 81343406Smckusick register struct file *wfp; 81443406Smckusick struct file *fp; 81543406Smckusick 81637586Smarc /* 81743406Smckusick * If the to-be-dup'd fd number is greater than the allowed number 81843406Smckusick * of file descriptors, or the fd to be dup'd has already been 81943406Smckusick * closed, reject. Note, check for new == old is necessary as 82043406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor 82143406Smckusick * as the new descriptor. 82237586Smarc */ 82347653Skarels fp = fdp->fd_ofiles[indx]; 82447653Skarels if ((u_int)dfd >= fdp->fd_nfiles || 82547653Skarels (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp) 82637586Smarc return (EBADF); 82740873Sbostic 82837586Smarc /* 82953826Spendry * There are two cases of interest here. 83053826Spendry * 83153826Spendry * For ENODEV simply dup (dfd) to file descriptor 83253826Spendry * (indx) and return. 83353826Spendry * 83453826Spendry * For ENXIO steal away the file structure from (dfd) and 83553826Spendry * store it in (indx). (dfd) is effectively closed by 83653826Spendry * this operation. 83753826Spendry * 83853826Spendry * Any other error code is just returned. 83937586Smarc */ 84053826Spendry switch (error) { 84153826Spendry case ENODEV: 84253826Spendry /* 84353826Spendry * Check that the mode the file is being opened for is a 84453826Spendry * subset of the mode of the existing descriptor. 84553826Spendry */ 84653826Spendry if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) 84753826Spendry return (EACCES); 84853826Spendry fdp->fd_ofiles[indx] = wfp; 84953826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 85053826Spendry wfp->f_count++; 85153826Spendry if (indx > fdp->fd_lastfile) 85253826Spendry fdp->fd_lastfile = indx; 85353826Spendry return (0); 85453826Spendry 85553826Spendry case ENXIO: 85653826Spendry /* 85753826Spendry * Steal away the file pointer from dfd, and stuff it into indx. 85853826Spendry */ 85953826Spendry fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd]; 86053826Spendry fdp->fd_ofiles[dfd] = NULL; 86153826Spendry fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 86253826Spendry fdp->fd_ofileflags[dfd] = 0; 86353826Spendry /* 86453826Spendry * Complete the clean up of the filedesc structure by 86553826Spendry * recomputing the various hints. 86653826Spendry */ 86753826Spendry if (indx > fdp->fd_lastfile) 86853826Spendry fdp->fd_lastfile = indx; 86953826Spendry else 87053826Spendry while (fdp->fd_lastfile > 0 && 87153826Spendry fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 87253826Spendry fdp->fd_lastfile--; 87353826Spendry if (dfd < fdp->fd_freefile) 87453826Spendry fdp->fd_freefile = dfd; 87553826Spendry return (0); 87653826Spendry 87753826Spendry default: 87853826Spendry return (error); 87953826Spendry } 88053826Spendry /* NOTREACHED */ 88137586Smarc } 882