123367Smckusick /* 247653Skarels * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. 337728Smckusick * All rights reserved. 423367Smckusick * 544431Sbostic * %sccs.include.redist.c% 637728Smckusick * 7*48029Smckusick * @(#)kern_descrip.c 7.23 (Berkeley) 04/16/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" 2447653Skarels #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 || 6547653Skarels (fp = fdp->fd_ofiles[uap->i]) == NULL) 6644404Skarels return (EBADF); 6747540Skarels if (error = fdalloc(p, 0, &fd)) 6844404Skarels return (error); 6947653Skarels fdp->fd_ofiles[fd] = fp; 7047653Skarels 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; 8447653Skarels struct args { 8547653Skarels u_int from; 8647653Skarels u_int to; 8742863Smckusick } *uap; 8842863Smckusick int *retval; 897497Sroot { 9045914Smckusick register struct filedesc *fdp = p->p_fd; 917497Sroot register struct file *fp; 9247653Skarels register u_int old = uap->from, new = uap->to; 9345914Smckusick int i, error; 947422Sroot 9547653Skarels if (old >= fdp->fd_nfiles || 9647653Skarels (fp = fdp->fd_ofiles[old]) == NULL || 9747653Skarels new >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) 9844404Skarels return (EBADF); 9947653Skarels *retval = new; 10047653Skarels if (old == new) 10144404Skarels return (0); 10247653Skarels if (new >= fdp->fd_nfiles) { 10347653Skarels if (error = fdalloc(p, new, &i)) 10445914Smckusick return (error); 10547653Skarels if (new != i) 10647540Skarels panic("dup2: fdalloc"); 10747653Skarels } else if (fdp->fd_ofiles[new]) { 10847653Skarels if (fdp->fd_ofileflags[new] & UF_MAPPED) 10947653Skarels (void) munmapfd(p, new); 11047653Skarels /* 11147653Skarels * dup2() must succeed even if the close has an error. 11247653Skarels */ 11347653Skarels (void) closef(fdp->fd_ofiles[new], p); 1147422Sroot } 11547653Skarels fdp->fd_ofiles[new] = fp; 11647653Skarels fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; 11742863Smckusick fp->f_count++; 11847653Skarels if (new > fdp->fd_lastfile) 11947653Skarels fdp->fd_lastfile = new; 12047653Skarels 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; 140*48029Smckusick int i, tmp, error, flg = F_POSIX; 14146200Smckusick struct flock fl; 1427497Sroot 14347540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 14447653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 14544404Skarels return (EBADF); 14647653Skarels 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); 15347653Skarels fdp->fd_ofiles[i] = fp; 15447653Skarels 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; 176*48029Smckusick if (tmp = (fp->f_flag & FNDELAY)) 177*48029Smckusick fp->f_flag |= FNDELAY; 178*48029Smckusick else 179*48029Smckusick fp->f_flag &= ~FNDELAY; 180*48029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 181*48029Smckusick if (error) 18244404Skarels return (error); 183*48029Smckusick if (tmp = (fp->f_flag & FASYNC)) 184*48029Smckusick fp->f_flag |= FASYNC; 185*48029Smckusick else 186*48029Smckusick fp->f_flag &= ~FASYNC; 187*48029Smckusick error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); 188*48029Smckusick if (!error) 189*48029Smckusick return (0); 190*48029Smckusick fp->f_flag &= ~FNDELAY; 191*48029Smckusick tmp = 0; 192*48029Smckusick (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 19344404Skarels return (error); 1947422Sroot 19515076Skarels case F_GETOWN: 196*48029Smckusick if (fp->f_type == DTYPE_SOCKET) { 197*48029Smckusick *retval = ((struct socket *)fp->f_data)->so_pgid; 198*48029Smckusick return (0); 199*48029Smckusick } 200*48029Smckusick error = (*fp->f_ops->fo_ioctl) 201*48029Smckusick (fp, (int)TIOCGPGRP, (caddr_t)retval, p); 202*48029Smckusick *retval = -*retval; 203*48029Smckusick return (error); 2047422Sroot 20515076Skarels case F_SETOWN: 206*48029Smckusick if (fp->f_type == DTYPE_SOCKET) { 207*48029Smckusick ((struct socket *)fp->f_data)->so_pgid = uap->arg; 208*48029Smckusick return (0); 209*48029Smckusick } 210*48029Smckusick if (uap->arg <= 0) { 211*48029Smckusick uap->arg = -uap->arg; 212*48029Smckusick } else { 213*48029Smckusick struct proc *p1 = pfind(uap->arg); 214*48029Smckusick if (p1 == 0) 215*48029Smckusick return (ESRCH); 216*48029Smckusick uap->arg = p1->p_pgrp->pg_id; 217*48029Smckusick } 218*48029Smckusick return ((*fp->f_ops->fo_ioctl) 219*48029Smckusick (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p)); 2208115Sroot 22146200Smckusick case F_SETLKW: 222*48029Smckusick flg |= F_WAIT; 22346200Smckusick /* Fall into F_SETLK */ 22446200Smckusick 22546200Smckusick case F_SETLK: 22646200Smckusick if (fp->f_type != DTYPE_VNODE) 22746200Smckusick return (EBADF); 22846200Smckusick vp = (struct vnode *)fp->f_data; 22946200Smckusick /* Copy in the lock structure */ 23046200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 23146200Smckusick if (error) 23246200Smckusick return (error); 23346200Smckusick if (fl.l_whence == SEEK_CUR) 23446200Smckusick fl.l_start += fp->f_offset; 23546200Smckusick switch (fl.l_type) { 23646200Smckusick 23746200Smckusick case F_RDLCK: 23846200Smckusick if ((fp->f_flag & FREAD) == 0) 23946200Smckusick return (EBADF); 240*48029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 24146200Smckusick 24246200Smckusick case F_WRLCK: 24346200Smckusick if ((fp->f_flag & FWRITE) == 0) 24446200Smckusick return (EBADF); 245*48029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); 24646200Smckusick 24746200Smckusick case F_UNLCK: 248*48029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl, 249*48029Smckusick F_POSIX)); 25046200Smckusick 25146200Smckusick default: 25246200Smckusick return (EINVAL); 25346200Smckusick } 25446200Smckusick 25546200Smckusick case F_GETLK: 25646200Smckusick if (fp->f_type != DTYPE_VNODE) 25746200Smckusick return (EBADF); 25846200Smckusick vp = (struct vnode *)fp->f_data; 25946200Smckusick /* Copy in the lock structure */ 26046200Smckusick error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); 26146200Smckusick if (error) 26246200Smckusick return (error); 26346765Smckusick if (fl.l_whence == SEEK_CUR) 26446765Smckusick fl.l_start += fp->f_offset; 265*48029Smckusick if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX)) 26646200Smckusick return (error); 26746200Smckusick return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl))); 26846200Smckusick 26912748Ssam default: 27044404Skarels return (EINVAL); 2717422Sroot } 27242863Smckusick /* NOTREACHED */ 2737422Sroot } 2747422Sroot 27542863Smckusick /* 27642863Smckusick * Close a file descriptor. 27742863Smckusick */ 27842863Smckusick /* ARGSUSED */ 27942863Smckusick close(p, uap, retval) 28042863Smckusick struct proc *p; 28142863Smckusick struct args { 28247540Skarels int fd; 28342863Smckusick } *uap; 28442863Smckusick int *retval; 2858029Sroot { 28645914Smckusick register struct filedesc *fdp = p->p_fd; 28712748Ssam register struct file *fp; 28847540Skarels register int fd = uap->fd; 28913044Ssam register u_char *pf; 2908029Sroot 29147540Skarels if ((unsigned)fd >= fdp->fd_nfiles || 29247653Skarels (fp = fdp->fd_ofiles[fd]) == NULL) 29344404Skarels return (EBADF); 29447653Skarels pf = (u_char *)&fdp->fd_ofileflags[fd]; 29513044Ssam if (*pf & UF_MAPPED) 29647540Skarels (void) munmapfd(p, fd); 29747653Skarels fdp->fd_ofiles[fd] = NULL; 29847653Skarels while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL) 29945914Smckusick fdp->fd_lastfile--; 30047540Skarels if (fd < fdp->fd_freefile) 30147540Skarels fdp->fd_freefile = fd; 30215550Skarels *pf = 0; 30347540Skarels return (closef(fp, p)); 3048029Sroot } 3058029Sroot 30642863Smckusick /* 30742863Smckusick * Return status information about a file descriptor. 30842863Smckusick */ 30942863Smckusick /* ARGSUSED */ 31042863Smckusick fstat(p, uap, retval) 31142863Smckusick struct proc *p; 31242863Smckusick register struct args { 31347540Skarels int fd; 31442863Smckusick struct stat *sb; 31542863Smckusick } *uap; 31642863Smckusick int *retval; 31713044Ssam { 31845914Smckusick register struct filedesc *fdp = p->p_fd; 31913044Ssam register struct file *fp; 32013044Ssam struct stat ub; 32142863Smckusick int error; 32213044Ssam 32347540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 32447653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 32544404Skarels return (EBADF); 32613044Ssam switch (fp->f_type) { 32713044Ssam 32837728Smckusick case DTYPE_VNODE: 329*48029Smckusick error = vn_stat((struct vnode *)fp->f_data, &ub, p); 33013044Ssam break; 33113044Ssam 33213044Ssam case DTYPE_SOCKET: 33342863Smckusick error = soo_stat((struct socket *)fp->f_data, &ub); 33413044Ssam break; 33513044Ssam 33613044Ssam default: 33713044Ssam panic("fstat"); 33813044Ssam /*NOTREACHED*/ 33913044Ssam } 34042863Smckusick if (error == 0) 34142863Smckusick error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); 34244404Skarels return (error); 34313044Ssam } 34413044Ssam 3457422Sroot /* 34647540Skarels * Allocate a file descriptor for the process. 3477422Sroot */ 34847540Skarels int fdexpand; 34945914Smckusick 35047540Skarels fdalloc(p, want, result) 35147540Skarels struct proc *p; 35247540Skarels int want; 35337728Smckusick int *result; 3547422Sroot { 35547540Skarels register struct filedesc *fdp = p->p_fd; 35647540Skarels register int i; 35747540Skarels int lim, last, nfiles; 35845914Smckusick struct file **newofile; 35945914Smckusick char *newofileflags; 3607497Sroot 36147540Skarels /* 36247540Skarels * Search for a free descriptor starting at the higher 36347540Skarels * of want or fd_freefile. If that fails, consider 36447540Skarels * expanding the ofile array. 36547540Skarels */ 36647540Skarels lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur; 36745914Smckusick for (;;) { 36847540Skarels last = min(fdp->fd_nfiles, lim); 36947540Skarels if ((i = want) < fdp->fd_freefile) 37047540Skarels i = fdp->fd_freefile; 37147540Skarels for (; i < last; i++) { 37247653Skarels if (fdp->fd_ofiles[i] == NULL) { 37347653Skarels fdp->fd_ofileflags[i] = 0; 37447540Skarels if (i > fdp->fd_lastfile) 37547540Skarels fdp->fd_lastfile = i; 37647653Skarels if (want <= fdp->fd_freefile) 37747540Skarels fdp->fd_freefile = i; 37847540Skarels *result = i; 37945914Smckusick return (0); 38045914Smckusick } 3817497Sroot } 38247540Skarels 38347540Skarels /* 38447540Skarels * No space in current array. Expand? 38547540Skarels */ 38647540Skarels if (fdp->fd_nfiles >= lim) 38745914Smckusick return (EMFILE); 38847653Skarels if (fdp->fd_nfiles < NDEXTENT) 38947653Skarels nfiles = NDEXTENT; 39047653Skarels else 39147653Skarels nfiles = 2 * fdp->fd_nfiles; 39247540Skarels MALLOC(newofile, struct file **, nfiles * OFILESIZE, 39347540Skarels M_FILEDESC, M_WAITOK); 39447540Skarels newofileflags = (char *) &newofile[nfiles]; 39547540Skarels /* 39647540Skarels * Copy the existing ofile and ofileflags arrays 39747540Skarels * and zero the new portion of each array. 39847540Skarels */ 39947540Skarels bcopy(fdp->fd_ofiles, newofile, 40047540Skarels (i = sizeof(struct file *) * fdp->fd_nfiles)); 40147540Skarels bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i); 40247540Skarels bcopy(fdp->fd_ofileflags, newofileflags, 40347540Skarels (i = sizeof(char) * fdp->fd_nfiles)); 40447540Skarels bzero(newofileflags + i, nfiles * sizeof(char) - i); 40547653Skarels if (fdp->fd_nfiles > NDFILE) 40647653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 40747540Skarels fdp->fd_ofiles = newofile; 40847540Skarels fdp->fd_ofileflags = newofileflags; 40947540Skarels fdp->fd_nfiles = nfiles; 41047540Skarels fdexpand++; 41139733Smckusick } 4127497Sroot } 4137497Sroot 41442863Smckusick /* 41547653Skarels * Check to see whether n user file descriptors 41647653Skarels * are available to the process p. 41742863Smckusick */ 41847540Skarels fdavail(p, n) 41947540Skarels struct proc *p; 42047540Skarels register int n; 42112748Ssam { 42247540Skarels register struct filedesc *fdp = p->p_fd; 42347653Skarels register struct file **fpp; 42447540Skarels register int i; 42512748Ssam 42647540Skarels if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 && 42747540Skarels (n -= i) <= 0) 42847540Skarels return (1); 42947653Skarels fpp = &fdp->fd_ofiles[fdp->fd_freefile]; 43047653Skarels for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++) 43147653Skarels if (*fpp == NULL && --n <= 0) 43247540Skarels return (1); 43347540Skarels return (0); 43412748Ssam } 43512748Ssam 4367497Sroot struct file *lastf; 4377497Sroot /* 43847540Skarels * Create a new open file structure and allocate 43947540Skarels * a file decriptor for the process that refers to it. 4407497Sroot */ 44145914Smckusick falloc(p, resultfp, resultfd) 44245914Smckusick register struct proc *p; 44337728Smckusick struct file **resultfp; 44437728Smckusick int *resultfd; 4457497Sroot { 4467422Sroot register struct file *fp; 44737728Smckusick int error, i; 4487422Sroot 44947540Skarels if (error = fdalloc(p, 0, &i)) 45037728Smckusick return (error); 4517497Sroot if (lastf == 0) 4527497Sroot lastf = file; 4537497Sroot for (fp = lastf; fp < fileNFILE; fp++) 4547497Sroot if (fp->f_count == 0) 4557497Sroot goto slot; 4567497Sroot for (fp = file; fp < lastf; fp++) 4577497Sroot if (fp->f_count == 0) 4587497Sroot goto slot; 4597497Sroot tablefull("file"); 46037728Smckusick return (ENFILE); 4617497Sroot slot: 46247653Skarels p->p_fd->fd_ofiles[i] = fp; 46312748Ssam fp->f_count = 1; 46412748Ssam fp->f_data = 0; 4657497Sroot fp->f_offset = 0; 46647540Skarels fp->f_cred = p->p_ucred; 46737728Smckusick crhold(fp->f_cred); 4687497Sroot lastf = fp + 1; 46937728Smckusick if (resultfp) 47037728Smckusick *resultfp = fp; 47137728Smckusick if (resultfd) 47237728Smckusick *resultfd = i; 47337728Smckusick return (0); 4747497Sroot } 47512748Ssam 4767497Sroot /* 47747540Skarels * Copy a filedesc structure. 47845914Smckusick */ 47945914Smckusick struct filedesc * 48047540Skarels fdcopy(p) 48147540Skarels struct proc *p; 48245914Smckusick { 48347653Skarels register struct filedesc *newfdp, *fdp = p->p_fd; 48447653Skarels register struct file **fpp; 48545914Smckusick register int i; 48645914Smckusick 48747653Skarels MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0), 48847653Skarels M_FILEDESC, M_WAITOK); 48947653Skarels bcopy(fdp, newfdp, sizeof(struct filedesc)); 49045914Smckusick VREF(newfdp->fd_cdir); 49145914Smckusick if (newfdp->fd_rdir) 49245914Smckusick VREF(newfdp->fd_rdir); 49345914Smckusick newfdp->fd_refcnt = 1; 49447540Skarels 49547540Skarels /* 49647653Skarels * If the number of open files fits in the internal arrays 49747653Skarels * of the open file structure, use them, otherwise allocate 49847653Skarels * additional memory for the number of descriptors currently 49947653Skarels * in use. 50047540Skarels */ 50147653Skarels if (newfdp->fd_lastfile < NDFILE) { 50247653Skarels newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles; 50347653Skarels newfdp->fd_ofileflags = 50447653Skarels ((struct filedesc0 *) newfdp)->fd_dfileflags; 50547653Skarels i = NDFILE; 50647653Skarels } else { 50747653Skarels /* 50847653Skarels * Compute the smallest multiple of NDEXTENT needed 50947653Skarels * for the file descriptors currently in use, 51047653Skarels * allowing the table to shrink. 51147653Skarels */ 51247653Skarels i = newfdp->fd_nfiles; 51347653Skarels while (i > 2 * NDEXTENT && i >= newfdp->fd_lastfile * 2) 51447653Skarels i /= 2; 51547653Skarels MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE, 51647653Skarels M_FILEDESC, M_WAITOK); 51747653Skarels newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; 51847653Skarels } 51947540Skarels newfdp->fd_nfiles = i; 52047540Skarels bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **)); 52147540Skarels bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char)); 52247653Skarels fpp = newfdp->fd_ofiles; 52347653Skarels for (i = newfdp->fd_lastfile; i-- >= 0; fpp++) 52447653Skarels if (*fpp != NULL) 52547653Skarels (*fpp)->f_count++; 52645914Smckusick return (newfdp); 52745914Smckusick } 52845914Smckusick 52945914Smckusick /* 53045914Smckusick * Release a filedesc structure. 53145914Smckusick */ 53247653Skarels void 53347540Skarels fdfree(p) 53447540Skarels struct proc *p; 53545914Smckusick { 53647540Skarels register struct filedesc *fdp = p->p_fd; 53747653Skarels struct file **fpp; 53845914Smckusick register int i; 53945914Smckusick 54047540Skarels if (--fdp->fd_refcnt > 0) 54145914Smckusick return; 54247653Skarels fpp = fdp->fd_ofiles; 54347653Skarels for (i = fdp->fd_lastfile; i-- >= 0; fpp++) 54447653Skarels if (*fpp) 54547653Skarels (void) closef(*fpp, p); 54647653Skarels if (fdp->fd_nfiles > NDFILE) 54747653Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 54845914Smckusick vrele(fdp->fd_cdir); 54945914Smckusick if (fdp->fd_rdir) 55045914Smckusick vrele(fdp->fd_rdir); 55147540Skarels FREE(fdp, M_FILEDESC); 55245914Smckusick } 55345914Smckusick 55445914Smckusick /* 5557497Sroot * Internal form of close. 55612748Ssam * Decrement reference count on file structure. 5577497Sroot */ 55847540Skarels closef(fp, p) 5597497Sroot register struct file *fp; 56047540Skarels struct proc *p; 5617497Sroot { 56246200Smckusick struct vnode *vp; 56346200Smckusick struct flock lf; 56439354Smckusick int error; 5657497Sroot 5667422Sroot if (fp == NULL) 56739354Smckusick return (0); 56846200Smckusick /* 56946200Smckusick * POSIX record locking dictates that any close releases ALL 57046200Smckusick * locks owned by this process. This is handled by setting 57146200Smckusick * a flag in the unlock to free ONLY locks obeying POSIX 57246200Smckusick * semantics, and not to free BSD-style file locks. 57346200Smckusick */ 57446200Smckusick if (fp->f_type == DTYPE_VNODE) { 57546200Smckusick lf.l_whence = SEEK_SET; 57646200Smckusick lf.l_start = 0; 57746200Smckusick lf.l_len = 0; 57846200Smckusick lf.l_type = F_UNLCK; 57946200Smckusick vp = (struct vnode *)fp->f_data; 580*48029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX); 58146200Smckusick } 58247540Skarels if (--fp->f_count > 0) 58339354Smckusick return (0); 58447540Skarels if (fp->f_count < 0) 58547540Skarels panic("closef: count < 0"); 58646200Smckusick if (fp->f_type == DTYPE_VNODE) 587*48029Smckusick (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); 588*48029Smckusick error = (*fp->f_ops->fo_close)(fp, p); 58937728Smckusick crfree(fp->f_cred); 5907497Sroot fp->f_count = 0; 59139354Smckusick return (error); 5927422Sroot } 59313044Ssam 59413044Ssam /* 59513044Ssam * Apply an advisory lock on a file descriptor. 59646200Smckusick * 59746200Smckusick * Just attempt to get a record lock of the requested type on 59846200Smckusick * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). 59913044Ssam */ 60046200Smckusick 60142863Smckusick /* ARGSUSED */ 60242863Smckusick flock(p, uap, retval) 60342863Smckusick struct proc *p; 60442863Smckusick register struct args { 60547540Skarels int fd; 60613044Ssam int how; 60742863Smckusick } *uap; 60842863Smckusick int *retval; 60942863Smckusick { 61045914Smckusick register struct filedesc *fdp = p->p_fd; 61113044Ssam register struct file *fp; 61246200Smckusick struct vnode *vp; 61346200Smckusick struct flock lf; 61446200Smckusick int error; 61513044Ssam 61647540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 61747653Skarels (fp = fdp->fd_ofiles[uap->fd]) == NULL) 61844404Skarels return (EBADF); 61942863Smckusick if (fp->f_type != DTYPE_VNODE) 62044404Skarels return (EOPNOTSUPP); 62146200Smckusick vp = (struct vnode *)fp->f_data; 62246200Smckusick lf.l_whence = SEEK_SET; 62346200Smckusick lf.l_start = 0; 62446200Smckusick lf.l_len = 0; 62513101Ssam if (uap->how & LOCK_UN) { 62646200Smckusick lf.l_type = F_UNLCK; 627*48029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK)); 62813044Ssam } 62917998Skarels if (uap->how & LOCK_EX) 63046200Smckusick lf.l_type = F_WRLCK; 63146200Smckusick else if (uap->how & LOCK_SH) 63246200Smckusick lf.l_type = F_RDLCK; 63346200Smckusick else 63446200Smckusick return (EBADF); 63546200Smckusick if (uap->how & LOCK_NB) 636*48029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK)); 637*48029Smckusick return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); 63813044Ssam } 63937586Smarc 64037586Smarc /* 64137586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 64237586Smarc * 64337586Smarc * Opening minor device N dup()s the file (if any) connected to file 64437586Smarc * descriptor N belonging to the calling process. Note that this driver 64537586Smarc * consists of only the ``open()'' routine, because all subsequent 64637586Smarc * references to this file will be direct to the other driver. 64737586Smarc */ 64837728Smckusick /* ARGSUSED */ 64937728Smckusick fdopen(dev, mode, type) 65037586Smarc dev_t dev; 65137728Smckusick int mode, type; 65237586Smarc { 65337586Smarc 65437586Smarc /* 65547540Skarels * XXX Kludge: set curproc->p_dupfd to contain the value of the 65643406Smckusick * the file descriptor being sought for duplication. The error 65743406Smckusick * return ensures that the vnode for this device will be released 65843406Smckusick * by vn_open. Open will detect this special error and take the 65943406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN 66043406Smckusick * will simply report the error. 66137586Smarc */ 66247540Skarels curproc->p_dupfd = minor(dev); /* XXX */ 66343406Smckusick return (ENODEV); 66443406Smckusick } 66540873Sbostic 66643406Smckusick /* 66743406Smckusick * Duplicate the specified descriptor to a free descriptor. 66843406Smckusick */ 66945914Smckusick dupfdopen(fdp, indx, dfd, mode) 67045914Smckusick register struct filedesc *fdp; 67143406Smckusick register int indx, dfd; 67243406Smckusick int mode; 67343406Smckusick { 67443406Smckusick register struct file *wfp; 67543406Smckusick struct file *fp; 67643406Smckusick 67737586Smarc /* 67843406Smckusick * If the to-be-dup'd fd number is greater than the allowed number 67943406Smckusick * of file descriptors, or the fd to be dup'd has already been 68043406Smckusick * closed, reject. Note, check for new == old is necessary as 68143406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor 68243406Smckusick * as the new descriptor. 68337586Smarc */ 68447653Skarels fp = fdp->fd_ofiles[indx]; 68547653Skarels if ((u_int)dfd >= fdp->fd_nfiles || 68647653Skarels (wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp) 68737586Smarc return (EBADF); 68840873Sbostic 68937586Smarc /* 69040873Sbostic * Check that the mode the file is being opened for is a subset 69140873Sbostic * of the mode of the existing descriptor. 69237586Smarc */ 69343406Smckusick if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) 69437586Smarc return (EACCES); 69547653Skarels fdp->fd_ofiles[indx] = wfp; 69647653Skarels fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; 69742863Smckusick wfp->f_count++; 69845914Smckusick if (indx > fdp->fd_lastfile) 69945914Smckusick fdp->fd_lastfile = indx; 70043406Smckusick return (0); 70137586Smarc } 702