123367Smckusick /* 2*47653Skarels * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. 337728Smckusick * All rights reserved. 423367Smckusick * 544431Sbostic * %sccs.include.redist.c% 637728Smckusick * 7*47653Skarels * @(#)kern_descrip.c 7.22 (Berkeley) 03/25/91 823367Smckusick */ 97422Sroot 1017089Sbloom #include "param.h" 1117089Sbloom #include "systm.h" 1245914Smckusick #include "filedesc.h" 1317089Sbloom #include "kernel.h" 1437728Smckusick #include "vnode.h" 1517089Sbloom #include "proc.h" 1617089Sbloom #include "file.h" 1717089Sbloom #include "socket.h" 1817089Sbloom #include "socketvar.h" 1917089Sbloom #include "stat.h" 2017089Sbloom #include "ioctl.h" 2146200Smckusick #include "fcntl.h" 2245914Smckusick #include "malloc.h" 2345914Smckusick #include "syslog.h" 24*47653Skarels #include "resourcevar.h" 257497Sroot 267422Sroot /* 277497Sroot * Descriptor management. 287422Sroot */ 297497Sroot 307497Sroot /* 317497Sroot * System calls on descriptors. 327497Sroot */ 3342863Smckusick /* ARGSUSED */ 3442863Smckusick getdtablesize(p, uap, retval) 3542863Smckusick struct proc *p; 3642863Smckusick struct args *uap; 3742863Smckusick int *retval; 387497Sroot { 397497Sroot 4047540Skarels *retval = p->p_rlimit[RLIMIT_OFILE].rlim_cur; 4144404Skarels return (0); 427497Sroot } 437497Sroot 4442863Smckusick /* 4542863Smckusick * Duplicate a file descriptor. 4642863Smckusick */ 4742863Smckusick /* ARGSUSED */ 4842863Smckusick dup(p, uap, retval) 4942863Smckusick struct proc *p; 5042863Smckusick struct args { 5142863Smckusick int i; 5242863Smckusick } *uap; 5342863Smckusick int *retval; 547422Sroot { 5545914Smckusick register struct filedesc *fdp = p->p_fd; 567696Ssam struct file *fp; 5742863Smckusick int fd, error; 587497Sroot 5942863Smckusick /* 6042863Smckusick * XXX Compatibility 6142863Smckusick */ 6244404Skarels if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); } 637497Sroot 6447540Skarels if ((unsigned)uap->i >= fdp->fd_nfiles || 65*47653Skarels (fp = fdp->fd_ofiles[uap->i]) == NULL) 6644404Skarels return (EBADF); 6747540Skarels if (error = fdalloc(p, 0, &fd)) 6844404Skarels return (error); 69*47653Skarels fdp->fd_ofiles[fd] = fp; 70*47653Skarels fdp->fd_ofileflags[fd] = fdp->fd_ofileflags[uap->i] &~ UF_EXCLOSE; 7142863Smckusick fp->f_count++; 7245914Smckusick if (fd > fdp->fd_lastfile) 7345914Smckusick fdp->fd_lastfile = fd; 7442863Smckusick *retval = fd; 7544404Skarels return (0); 767497Sroot } 777497Sroot 7842863Smckusick /* 7942863Smckusick * Duplicate a file descriptor to a particular value. 8042863Smckusick */ 8142863Smckusick /* ARGSUSED */ 8242863Smckusick dup2(p, uap, retval) 8342863Smckusick struct proc *p; 84*47653Skarels struct args { 85*47653Skarels u_int from; 86*47653Skarels u_int to; 8742863Smckusick } *uap; 8842863Smckusick int *retval; 897497Sroot { 9045914Smckusick register struct filedesc *fdp = p->p_fd; 917497Sroot register struct file *fp; 92*47653Skarels register u_int old = uap->from, new = uap->to; 9345914Smckusick int i, error; 947422Sroot 95*47653Skarels if (old >= fdp->fd_nfiles || 96*47653Skarels (fp = fdp->fd_ofiles[old]) == NULL || 97*47653Skarels new >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) 9844404Skarels return (EBADF); 99*47653Skarels *retval = new; 100*47653Skarels if (old == new) 10144404Skarels return (0); 102*47653Skarels if (new >= fdp->fd_nfiles) { 103*47653Skarels if (error = fdalloc(p, new, &i)) 10445914Smckusick return (error); 105*47653Skarels if (new != i) 10647540Skarels panic("dup2: fdalloc"); 107*47653Skarels } else if (fdp->fd_ofiles[new]) { 108*47653Skarels if (fdp->fd_ofileflags[new] & UF_MAPPED) 109*47653Skarels (void) munmapfd(p, new); 110*47653Skarels /* 111*47653Skarels * dup2() must succeed even if the close has an error. 112*47653Skarels */ 113*47653Skarels (void) closef(fdp->fd_ofiles[new], p); 1147422Sroot } 115*47653Skarels fdp->fd_ofiles[new] = fp; 116*47653Skarels fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; 11742863Smckusick fp->f_count++; 118*47653Skarels if (new > fdp->fd_lastfile) 119*47653Skarels fdp->fd_lastfile = new; 120*47653Skarels return (0); 1217696Ssam } 1227696Ssam 12312748Ssam /* 12412748Ssam * The file control system call. 12512748Ssam */ 12642863Smckusick /* ARGSUSED */ 12742863Smckusick fcntl(p, uap, retval) 12842863Smckusick struct proc *p; 12942863Smckusick register struct args { 13047540Skarels int fd; 13112748Ssam int cmd; 13212748Ssam int arg; 13342863Smckusick } *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; 14046200Smckusick int i, error, flags = F_POSIX; 14146200Smckusick struct flock fl; 1427497Sroot 14347540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 144*47653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 14544404Skarels return (EBADF); 146*47653Skarels pop = &fdp->fd_ofileflags[uap->fd]; 14712748Ssam switch(uap->cmd) { 14815076Skarels case F_DUPFD: 14947540Skarels if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) 15044404Skarels return (EINVAL); 15147540Skarels if (error = fdalloc(p, uap->arg, &i)) 15244404Skarels return (error); 153*47653Skarels fdp->fd_ofiles[i] = fp; 154*47653Skarels fdp->fd_ofileflags[i] = *pop &~ UF_EXCLOSE; 15542863Smckusick fp->f_count++; 15645914Smckusick if (i > fdp->fd_lastfile) 15745914Smckusick fdp->fd_lastfile = i; 15842863Smckusick *retval = i; 15944404Skarels return (0); 1607497Sroot 16115076Skarels case F_GETFD: 16242863Smckusick *retval = *pop & 1; 16344404Skarels return (0); 1647422Sroot 16515076Skarels case F_SETFD: 16612748Ssam *pop = (*pop &~ 1) | (uap->arg & 1); 16744404Skarels return (0); 1688145Sroot 16915076Skarels case F_GETFL: 17046495Skarels *retval = OFLAGS(fp->f_flag); 17144404Skarels return (0); 1728145Sroot 17315076Skarels case F_SETFL: 17446495Skarels fp->f_flag &= ~FCNTLFLAGS; 17546495Skarels fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS; 17642863Smckusick if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY)) 17744404Skarels return (error); 17842863Smckusick if (error = fset(fp, FASYNC, fp->f_flag & FASYNC)) 17912748Ssam (void) fset(fp, FNDELAY, 0); 18044404Skarels return (error); 1817422Sroot 18215076Skarels case F_GETOWN: 18344404Skarels return (fgetown(fp, retval)); 1847422Sroot 18515076Skarels case F_SETOWN: 18644404Skarels return (fsetown(fp, uap->arg)); 1878115Sroot 18846200Smckusick case F_SETLKW: 18946200Smckusick flags |= F_WAIT; 19046200Smckusick /* Fall into F_SETLK */ 19146200Smckusick 19246200Smckusick case F_SETLK: 19346200Smckusick if (fp->f_type != DTYPE_VNODE) 19446200Smckusick return (EBADF); 19546200Smckusick vp = (struct vnode *)fp->f_data; 19646200Smckusick /* Copy in the lock structure */ 19746200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 19846200Smckusick if (error) 19946200Smckusick return (error); 20046200Smckusick if (fl.l_whence == SEEK_CUR) 20146200Smckusick fl.l_start += fp->f_offset; 20246200Smckusick switch (fl.l_type) { 20346200Smckusick 20446200Smckusick case F_RDLCK: 20546200Smckusick if ((fp->f_flag & FREAD) == 0) 20646200Smckusick return (EBADF); 20746200Smckusick return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags)); 20846200Smckusick 20946200Smckusick case F_WRLCK: 21046200Smckusick if ((fp->f_flag & FWRITE) == 0) 21146200Smckusick return (EBADF); 21246200Smckusick return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags)); 21346200Smckusick 21446200Smckusick case F_UNLCK: 21546200Smckusick return (VOP_ADVLOCK(vp, p, F_UNLCK, &fl, F_POSIX)); 21646200Smckusick 21746200Smckusick default: 21846200Smckusick return (EINVAL); 21946200Smckusick } 22046200Smckusick 22146200Smckusick case F_GETLK: 22246200Smckusick if (fp->f_type != DTYPE_VNODE) 22346200Smckusick return (EBADF); 22446200Smckusick vp = (struct vnode *)fp->f_data; 22546200Smckusick /* Copy in the lock structure */ 22646200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 22746200Smckusick if (error) 22846200Smckusick return (error); 22946765Smckusick if (fl.l_whence == SEEK_CUR) 23046765Smckusick fl.l_start += fp->f_offset; 23146200Smckusick if (error = VOP_ADVLOCK(vp, p, F_GETLK, &fl, F_POSIX)) 23246200Smckusick return (error); 23346200Smckusick return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl))); 23446200Smckusick 23512748Ssam default: 23644404Skarels return (EINVAL); 2377422Sroot } 23842863Smckusick /* NOTREACHED */ 2397422Sroot } 2407422Sroot 24112748Ssam fset(fp, bit, value) 24212748Ssam struct file *fp; 24312748Ssam int bit, value; 2447422Sroot { 2457422Sroot 24612748Ssam if (value) 24712748Ssam fp->f_flag |= bit; 24812748Ssam else 24912748Ssam fp->f_flag &= ~bit; 25012748Ssam return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC), 25112748Ssam (caddr_t)&value)); 25212748Ssam } 2537422Sroot 25412748Ssam fgetown(fp, valuep) 25512748Ssam struct file *fp; 25612748Ssam int *valuep; 25712748Ssam { 25812748Ssam int error; 2598115Sroot 26012748Ssam switch (fp->f_type) { 2618115Sroot 26212748Ssam case DTYPE_SOCKET: 26335810Smarc *valuep = ((struct socket *)fp->f_data)->so_pgid; 26412748Ssam return (0); 2657497Sroot 26612748Ssam default: 26712748Ssam error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep); 26812748Ssam *valuep = -*valuep; 26912748Ssam return (error); 2707422Sroot } 2717422Sroot } 2727422Sroot 27312748Ssam fsetown(fp, value) 27412748Ssam struct file *fp; 27512748Ssam int value; 2767422Sroot { 27737728Smckusick 27812748Ssam if (fp->f_type == DTYPE_SOCKET) { 27935810Smarc ((struct socket *)fp->f_data)->so_pgid = value; 28012748Ssam return (0); 28112748Ssam } 28212748Ssam if (value > 0) { 28312748Ssam struct proc *p = pfind(value); 28412748Ssam if (p == 0) 28528201Skarels return (ESRCH); 28635810Smarc value = p->p_pgrp->pg_id; 28712748Ssam } else 28812748Ssam value = -value; 28912748Ssam return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value)); 2907422Sroot } 2917422Sroot 29212748Ssam fioctl(fp, cmd, value) 29312748Ssam struct file *fp; 29412748Ssam int cmd; 29512748Ssam caddr_t value; 2967422Sroot { 2977422Sroot 29812748Ssam return ((*fp->f_ops->fo_ioctl)(fp, cmd, value)); 2997422Sroot } 3007422Sroot 30142863Smckusick /* 30242863Smckusick * Close a file descriptor. 30342863Smckusick */ 30442863Smckusick /* ARGSUSED */ 30542863Smckusick close(p, uap, retval) 30642863Smckusick struct proc *p; 30742863Smckusick struct args { 30847540Skarels int fd; 30942863Smckusick } *uap; 31042863Smckusick int *retval; 3118029Sroot { 31245914Smckusick register struct filedesc *fdp = p->p_fd; 31312748Ssam register struct file *fp; 31447540Skarels register int fd = uap->fd; 31513044Ssam register u_char *pf; 3168029Sroot 31747540Skarels if ((unsigned)fd >= fdp->fd_nfiles || 318*47653Skarels (fp = fdp->fd_ofiles[fd]) == NULL) 31944404Skarels return (EBADF); 320*47653Skarels pf = (u_char *)&fdp->fd_ofileflags[fd]; 32113044Ssam if (*pf & UF_MAPPED) 32247540Skarels (void) munmapfd(p, fd); 323*47653Skarels fdp->fd_ofiles[fd] = NULL; 324*47653Skarels while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 32545914Smckusick fdp->fd_lastfile--; 32647540Skarels if (fd < fdp->fd_freefile) 32747540Skarels fdp->fd_freefile = fd; 32815550Skarels *pf = 0; 32947540Skarels return (closef(fp, p)); 3308029Sroot } 3318029Sroot 33242863Smckusick /* 33342863Smckusick * Return status information about a file descriptor. 33442863Smckusick */ 33542863Smckusick /* ARGSUSED */ 33642863Smckusick fstat(p, uap, retval) 33742863Smckusick struct proc *p; 33842863Smckusick register struct args { 33947540Skarels int fd; 34042863Smckusick struct stat *sb; 34142863Smckusick } *uap; 34242863Smckusick int *retval; 34313044Ssam { 34445914Smckusick register struct filedesc *fdp = p->p_fd; 34513044Ssam register struct file *fp; 34613044Ssam struct stat ub; 34742863Smckusick int error; 34813044Ssam 34947540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 350*47653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 35144404Skarels return (EBADF); 35213044Ssam switch (fp->f_type) { 35313044Ssam 35437728Smckusick case DTYPE_VNODE: 35542863Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub); 35613044Ssam break; 35713044Ssam 35813044Ssam case DTYPE_SOCKET: 35942863Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 36013044Ssam break; 36113044Ssam 36213044Ssam default: 36313044Ssam panic("fstat"); 36413044Ssam /*NOTREACHED*/ 36513044Ssam } 36642863Smckusick if (error == 0) 36742863Smckusick error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); 36844404Skarels return (error); 36913044Ssam } 37013044Ssam 3717422Sroot /* 37247540Skarels * Allocate a file descriptor for the process. 3737422Sroot */ 37447540Skarels int fdexpand; 37545914Smckusick 37647540Skarels fdalloc(p, want, result) 37747540Skarels struct proc *p; 37847540Skarels int want; 37937728Smckusick int *result; 3807422Sroot { 38147540Skarels register struct filedesc *fdp = p->p_fd; 38247540Skarels register int i; 38347540Skarels int lim, last, nfiles; 38445914Smckusick struct file **newofile; 38545914Smckusick char *newofileflags; 3867497Sroot 38747540Skarels /* 38847540Skarels * Search for a free descriptor starting at the higher 38947540Skarels * of want or fd_freefile. If that fails, consider 39047540Skarels * expanding the ofile array. 39147540Skarels */ 39247540Skarels lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur; 39345914Smckusick for (;;) { 39447540Skarels last = min(fdp->fd_nfiles, lim); 39547540Skarels if ((i = want) < fdp->fd_freefile) 39647540Skarels i = fdp->fd_freefile; 39747540Skarels for (; i < last; i++) { 398*47653Skarels if (fdp->fd_ofiles[i] == NULL) { 399*47653Skarels fdp->fd_ofileflags[i] = 0; 40047540Skarels if (i > fdp->fd_lastfile) 40147540Skarels fdp->fd_lastfile = i; 402*47653Skarels if (want <= fdp->fd_freefile) 40347540Skarels fdp->fd_freefile = i; 40447540Skarels *result = i; 40545914Smckusick return (0); 40645914Smckusick } 4077497Sroot } 40847540Skarels 40947540Skarels /* 41047540Skarels * No space in current array. Expand? 41147540Skarels */ 41247540Skarels if (fdp->fd_nfiles >= lim) 41345914Smckusick return (EMFILE); 414*47653Skarels if (fdp->fd_nfiles < NDEXTENT) 415*47653Skarels nfiles = NDEXTENT; 416*47653Skarels else 417*47653Skarels nfiles = 2 * fdp->fd_nfiles; 41847540Skarels MALLOC(newofile, struct file **, nfiles * OFILESIZE, 41947540Skarels M_FILEDESC, M_WAITOK); 42047540Skarels newofileflags = (char *) &newofile[nfiles]; 42147540Skarels /* 42247540Skarels * Copy the existing ofile and ofileflags arrays 42347540Skarels * and zero the new portion of each array. 42447540Skarels */ 42547540Skarels bcopy(fdp->fd_ofiles, newofile, 42647540Skarels (i = sizeof(struct file *) * fdp->fd_nfiles)); 42747540Skarels bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i); 42847540Skarels bcopy(fdp->fd_ofileflags, newofileflags, 42947540Skarels (i = sizeof(char) * fdp->fd_nfiles)); 43047540Skarels bzero(newofileflags + i, nfiles * sizeof(char) - i); 431*47653Skarels if (fdp->fd_nfiles > NDFILE) 432*47653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 43347540Skarels fdp->fd_ofiles = newofile; 43447540Skarels fdp->fd_ofileflags = newofileflags; 43547540Skarels fdp->fd_nfiles = nfiles; 43647540Skarels fdexpand++; 43739733Smckusick } 4387497Sroot } 4397497Sroot 44042863Smckusick /* 441*47653Skarels * Check to see whether n user file descriptors 442*47653Skarels * are available to the process p. 44342863Smckusick */ 44447540Skarels fdavail(p, n) 44547540Skarels struct proc *p; 44647540Skarels register int n; 44712748Ssam { 44847540Skarels register struct filedesc *fdp = p->p_fd; 449*47653Skarels register struct file **fpp; 45047540Skarels register int i; 45112748Ssam 45247540Skarels if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 && 45347540Skarels (n -= i) <= 0) 45447540Skarels return (1); 455*47653Skarels fpp = &fdp->fd_ofiles[fdp->fd_freefile]; 456*47653Skarels for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++) 457*47653Skarels if (*fpp == NULL && --n <= 0) 45847540Skarels return (1); 45947540Skarels return (0); 46012748Ssam } 46112748Ssam 4627497Sroot struct file *lastf; 4637497Sroot /* 46447540Skarels * Create a new open file structure and allocate 46547540Skarels * a file decriptor for the process that refers to it. 4667497Sroot */ 46745914Smckusick falloc(p, resultfp, resultfd) 46845914Smckusick register struct proc *p; 46937728Smckusick struct file **resultfp; 47037728Smckusick int *resultfd; 4717497Sroot { 4727422Sroot register struct file *fp; 47337728Smckusick int error, i; 4747422Sroot 47547540Skarels if (error = fdalloc(p, 0, &i)) 47637728Smckusick return (error); 4777497Sroot if (lastf == 0) 4787497Sroot lastf = file; 4797497Sroot for (fp = lastf; fp < fileNFILE; fp++) 4807497Sroot if (fp->f_count == 0) 4817497Sroot goto slot; 4827497Sroot for (fp = file; fp < lastf; fp++) 4837497Sroot if (fp->f_count == 0) 4847497Sroot goto slot; 4857497Sroot tablefull("file"); 48637728Smckusick return (ENFILE); 4877497Sroot slot: 488*47653Skarels p->p_fd->fd_ofiles[i] = fp; 48912748Ssam fp->f_count = 1; 49012748Ssam fp->f_data = 0; 4917497Sroot fp->f_offset = 0; 49247540Skarels fp->f_cred = p->p_ucred; 49337728Smckusick crhold(fp->f_cred); 4947497Sroot lastf = fp + 1; 49537728Smckusick if (resultfp) 49637728Smckusick *resultfp = fp; 49737728Smckusick if (resultfd) 49837728Smckusick *resultfd = i; 49937728Smckusick return (0); 5007497Sroot } 50112748Ssam 5027497Sroot /* 50347540Skarels * Copy a filedesc structure. 50445914Smckusick */ 50545914Smckusick struct filedesc * 50647540Skarels fdcopy(p) 50747540Skarels struct proc *p; 50845914Smckusick { 509*47653Skarels register struct filedesc *newfdp, *fdp = p->p_fd; 510*47653Skarels register struct file **fpp; 51145914Smckusick register int i; 51245914Smckusick 513*47653Skarels MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0), 514*47653Skarels M_FILEDESC, M_WAITOK); 515*47653Skarels bcopy(fdp, newfdp, sizeof(struct filedesc)); 51645914Smckusick VREF(newfdp->fd_cdir); 51745914Smckusick if (newfdp->fd_rdir) 51845914Smckusick VREF(newfdp->fd_rdir); 51945914Smckusick newfdp->fd_refcnt = 1; 52047540Skarels 52147540Skarels /* 522*47653Skarels * If the number of open files fits in the internal arrays 523*47653Skarels * of the open file structure, use them, otherwise allocate 524*47653Skarels * additional memory for the number of descriptors currently 525*47653Skarels * in use. 52647540Skarels */ 527*47653Skarels if (newfdp->fd_lastfile < NDFILE) { 528*47653Skarels newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles; 529*47653Skarels newfdp->fd_ofileflags = 530*47653Skarels ((struct filedesc0 *) newfdp)->fd_dfileflags; 531*47653Skarels i = NDFILE; 532*47653Skarels } else { 533*47653Skarels /* 534*47653Skarels * Compute the smallest multiple of NDEXTENT needed 535*47653Skarels * for the file descriptors currently in use, 536*47653Skarels * allowing the table to shrink. 537*47653Skarels */ 538*47653Skarels i = newfdp->fd_nfiles; 539*47653Skarels while (i > 2 * NDEXTENT && i >= newfdp->fd_lastfile * 2) 540*47653Skarels i /= 2; 541*47653Skarels MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE, 542*47653Skarels M_FILEDESC, M_WAITOK); 543*47653Skarels newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; 544*47653Skarels } 54547540Skarels newfdp->fd_nfiles = i; 54647540Skarels bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **)); 54747540Skarels bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char)); 548*47653Skarels fpp = newfdp->fd_ofiles; 549*47653Skarels for (i = newfdp->fd_lastfile; i-- >= 0; fpp++) 550*47653Skarels if (*fpp != NULL) 551*47653Skarels (*fpp)->f_count++; 55245914Smckusick return (newfdp); 55345914Smckusick } 55445914Smckusick 55545914Smckusick /* 55645914Smckusick * Release a filedesc structure. 55745914Smckusick */ 558*47653Skarels void 55947540Skarels fdfree(p) 56047540Skarels struct proc *p; 56145914Smckusick { 56247540Skarels register struct filedesc *fdp = p->p_fd; 563*47653Skarels struct file **fpp; 56445914Smckusick register int i; 56545914Smckusick 56647540Skarels if (--fdp->fd_refcnt > 0) 56745914Smckusick return; 568*47653Skarels fpp = fdp->fd_ofiles; 569*47653Skarels for (i = fdp->fd_lastfile; i-- >= 0; fpp++) 570*47653Skarels if (*fpp) 571*47653Skarels (void) closef(*fpp, p); 572*47653Skarels if (fdp->fd_nfiles > NDFILE) 573*47653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 57445914Smckusick vrele(fdp->fd_cdir); 57545914Smckusick if (fdp->fd_rdir) 57645914Smckusick vrele(fdp->fd_rdir); 57747540Skarels FREE(fdp, M_FILEDESC); 57845914Smckusick } 57945914Smckusick 58045914Smckusick /* 5817497Sroot * Internal form of close. 58212748Ssam * Decrement reference count on file structure. 5837497Sroot */ 58447540Skarels closef(fp, p) 5857497Sroot register struct file *fp; 58647540Skarels struct proc *p; 5877497Sroot { 58846200Smckusick struct vnode *vp; 58946200Smckusick struct flock lf; 59039354Smckusick int error; 5917497Sroot 5927422Sroot if (fp == NULL) 59339354Smckusick return (0); 59446200Smckusick /* 59546200Smckusick * POSIX record locking dictates that any close releases ALL 59646200Smckusick * locks owned by this process. This is handled by setting 59746200Smckusick * a flag in the unlock to free ONLY locks obeying POSIX 59846200Smckusick * semantics, and not to free BSD-style file locks. 59946200Smckusick */ 60046200Smckusick if (fp->f_type == DTYPE_VNODE) { 60146200Smckusick lf.l_whence = SEEK_SET; 60246200Smckusick lf.l_start = 0; 60346200Smckusick lf.l_len = 0; 60446200Smckusick lf.l_type = F_UNLCK; 60546200Smckusick vp = (struct vnode *)fp->f_data; 60646200Smckusick (void) VOP_ADVLOCK(vp, p, F_UNLCK, &lf, F_POSIX); 60746200Smckusick } 60847540Skarels if (--fp->f_count > 0) 60939354Smckusick return (0); 61047540Skarels if (fp->f_count < 0) 61147540Skarels panic("closef: count < 0"); 61246200Smckusick if (fp->f_type == DTYPE_VNODE) 61346200Smckusick (void) VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK); 61439354Smckusick error = (*fp->f_ops->fo_close)(fp); 61537728Smckusick crfree(fp->f_cred); 6167497Sroot fp->f_count = 0; 61739354Smckusick return (error); 6187422Sroot } 61913044Ssam 62013044Ssam /* 62113044Ssam * Apply an advisory lock on a file descriptor. 62246200Smckusick * 62346200Smckusick * Just attempt to get a record lock of the requested type on 62446200Smckusick * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). 62513044Ssam */ 62646200Smckusick 62742863Smckusick /* ARGSUSED */ 62842863Smckusick flock(p, uap, retval) 62942863Smckusick struct proc *p; 63042863Smckusick register struct args { 63147540Skarels int fd; 63213044Ssam int how; 63342863Smckusick } *uap; 63442863Smckusick int *retval; 63542863Smckusick { 63645914Smckusick register struct filedesc *fdp = p->p_fd; 63713044Ssam register struct file *fp; 63846200Smckusick struct vnode *vp; 63946200Smckusick struct flock lf; 64046200Smckusick int error; 64113044Ssam 64247540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 643*47653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 64444404Skarels return (EBADF); 64542863Smckusick if (fp->f_type != DTYPE_VNODE) 64644404Skarels return (EOPNOTSUPP); 64746200Smckusick vp = (struct vnode *)fp->f_data; 64846200Smckusick lf.l_whence = SEEK_SET; 64946200Smckusick lf.l_start = 0; 65046200Smckusick lf.l_len = 0; 65113101Ssam if (uap->how & LOCK_UN) { 65246200Smckusick lf.l_type = F_UNLCK; 65346200Smckusick return (VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK)); 65413044Ssam } 65517998Skarels if (uap->how & LOCK_EX) 65646200Smckusick lf.l_type = F_WRLCK; 65746200Smckusick else if (uap->how & LOCK_SH) 65846200Smckusick lf.l_type = F_RDLCK; 65946200Smckusick else 66046200Smckusick return (EBADF); 66146200Smckusick if (uap->how & LOCK_NB) 66246200Smckusick return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK)); 66346200Smckusick return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); 66413044Ssam } 66537586Smarc 66637586Smarc /* 66737586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 66837586Smarc * 66937586Smarc * Opening minor device N dup()s the file (if any) connected to file 67037586Smarc * descriptor N belonging to the calling process. Note that this driver 67137586Smarc * consists of only the ``open()'' routine, because all subsequent 67237586Smarc * references to this file will be direct to the other driver. 67337586Smarc */ 67437728Smckusick /* ARGSUSED */ 67537728Smckusick fdopen(dev, mode, type) 67637586Smarc dev_t dev; 67737728Smckusick int mode, type; 67837586Smarc { 67937586Smarc 68037586Smarc /* 68147540Skarels * XXX Kludge: set curproc->p_dupfd to contain the value of the 68243406Smckusick * the file descriptor being sought for duplication. The error 68343406Smckusick * return ensures that the vnode for this device will be released 68443406Smckusick * by vn_open. Open will detect this special error and take the 68543406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN 68643406Smckusick * will simply report the error. 68737586Smarc */ 68847540Skarels curproc->p_dupfd = minor(dev); /* XXX */ 68943406Smckusick return (ENODEV); 69043406Smckusick } 69140873Sbostic 69243406Smckusick /* 69343406Smckusick * Duplicate the specified descriptor to a free descriptor. 69443406Smckusick */ 69545914Smckusick dupfdopen(fdp, indx, dfd, mode) 69645914Smckusick register struct filedesc *fdp; 69743406Smckusick register int indx, dfd; 69843406Smckusick int mode; 69943406Smckusick { 70043406Smckusick register struct file *wfp; 70143406Smckusick struct file *fp; 70243406Smckusick 70337586Smarc /* 70443406Smckusick * If the to-be-dup'd fd number is greater than the allowed number 70543406Smckusick * of file descriptors, or the fd to be dup'd has already been 70643406Smckusick * closed, reject. Note, check for new == old is necessary as 70743406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor 70843406Smckusick * as the new descriptor. 70937586Smarc */ 710*47653Skarels fp = fdp->fd_ofiles[indx]; 711*47653Skarels if ((u_int)dfd >= fdp->fd_nfiles || 712*47653Skarels (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp) 71337586Smarc return (EBADF); 71440873Sbostic 71537586Smarc /* 71640873Sbostic * Check that the mode the file is being opened for is a subset 71740873Sbostic * of the mode of the existing descriptor. 71837586Smarc */ 71943406Smckusick if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) 72037586Smarc return (EACCES); 721*47653Skarels fdp->fd_ofiles[indx] = wfp; 722*47653Skarels fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 72342863Smckusick wfp->f_count++; 72445914Smckusick if (indx > fdp->fd_lastfile) 72545914Smckusick fdp->fd_lastfile = indx; 72643406Smckusick return (0); 72737586Smarc } 728