123367Smckusick /* 237728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337728Smckusick * All rights reserved. 423367Smckusick * 544431Sbostic * %sccs.include.redist.c% 637728Smckusick * 7*47540Skarels * @(#)kern_descrip.c 7.21 (Berkeley) 03/17/91 823367Smckusick */ 97422Sroot 1017089Sbloom #include "param.h" 1117089Sbloom #include "systm.h" 1244404Skarels #include "user.h" 1345914Smckusick #include "filedesc.h" 1417089Sbloom #include "kernel.h" 1537728Smckusick #include "vnode.h" 1617089Sbloom #include "proc.h" 1717089Sbloom #include "file.h" 1817089Sbloom #include "socket.h" 1917089Sbloom #include "socketvar.h" 2017089Sbloom #include "stat.h" 2117089Sbloom #include "ioctl.h" 2246200Smckusick #include "fcntl.h" 2345914Smckusick #include "malloc.h" 2445914Smckusick #include "syslog.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 40*47540Skarels *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 64*47540Skarels if ((unsigned)uap->i >= fdp->fd_nfiles || 6545914Smckusick (fp = OFILE(fdp, uap->i)) == NULL) 6644404Skarels return (EBADF); 67*47540Skarels if (error = fdalloc(p, 0, &fd)) 6844404Skarels return (error); 6945914Smckusick OFILE(fdp, fd) = fp; 7045914Smckusick OFILEFLAGS(fdp, fd) = OFILEFLAGS(fdp, 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; 8442863Smckusick register struct args { 8542863Smckusick int i; 8642863Smckusick int j; 8742863Smckusick } *uap; 8842863Smckusick int *retval; 897497Sroot { 9045914Smckusick register struct filedesc *fdp = p->p_fd; 917497Sroot register struct file *fp; 9245914Smckusick int i, error; 937422Sroot 94*47540Skarels if ((unsigned)uap->i >= fdp->fd_nfiles || 9545914Smckusick (fp = OFILE(fdp, uap->i)) == NULL || 96*47540Skarels (unsigned)uap->j >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) 9744404Skarels return (EBADF); 9842863Smckusick *retval = uap->j; 997497Sroot if (uap->i == uap->j) 10044404Skarels return (0); 101*47540Skarels if ((unsigned)uap->j >= fdp->fd_nfiles) { 102*47540Skarels if (error = fdalloc(p, uap->j, &i)) 10345914Smckusick return (error); 10445914Smckusick if (uap->j != i) 105*47540Skarels panic("dup2: fdalloc"); 10645914Smckusick } else if (OFILE(fdp, uap->j)) { 10745914Smckusick if (OFILEFLAGS(fdp, uap->j) & UF_MAPPED) 10845914Smckusick (void) munmapfd(p, uap->j); 109*47540Skarels error = closef(OFILE(fdp, uap->j), p); 1107422Sroot } 11145914Smckusick OFILE(fdp, uap->j) = fp; 11245914Smckusick OFILEFLAGS(fdp, uap->j) = OFILEFLAGS(fdp, uap->i) &~ UF_EXCLOSE; 11342863Smckusick fp->f_count++; 11445914Smckusick if (uap->j > fdp->fd_lastfile) 11545914Smckusick fdp->fd_lastfile = uap->j; 11639354Smckusick /* 11739354Smckusick * dup2() must succeed even though the close had an error. 11839354Smckusick */ 11939354Smckusick error = 0; /* XXX */ 12044404Skarels return (error); 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 { 130*47540Skarels 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 143*47540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 144*47540Skarels (fp = OFILE(fdp, uap->fd)) == NULL) 14544404Skarels return (EBADF); 146*47540Skarels pop = &OFILEFLAGS(fdp, uap->fd); 14712748Ssam switch(uap->cmd) { 14815076Skarels case F_DUPFD: 149*47540Skarels if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) 15044404Skarels return (EINVAL); 151*47540Skarels if (error = fdalloc(p, uap->arg, &i)) 15244404Skarels return (error); 15345914Smckusick OFILE(fdp, i) = fp; 15445914Smckusick OFILEFLAGS(fdp, 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 { 308*47540Skarels int fd; 30942863Smckusick } *uap; 31042863Smckusick int *retval; 3118029Sroot { 31245914Smckusick register struct filedesc *fdp = p->p_fd; 31312748Ssam register struct file *fp; 314*47540Skarels register int fd = uap->fd; 31513044Ssam register u_char *pf; 3168029Sroot 317*47540Skarels if ((unsigned)fd >= fdp->fd_nfiles || 318*47540Skarels (fp = OFILE(fdp, fd)) == NULL) 31944404Skarels return (EBADF); 320*47540Skarels pf = (u_char *)&OFILEFLAGS(fdp, fd); 32113044Ssam if (*pf & UF_MAPPED) 322*47540Skarels (void) munmapfd(p, fd); 323*47540Skarels OFILE(fdp, fd) = NULL; 32445914Smckusick while (fdp->fd_lastfile >= 0 && OFILE(fdp, fdp->fd_lastfile) == NULL) 32545914Smckusick fdp->fd_lastfile--; 326*47540Skarels if (fd < fdp->fd_freefile) 327*47540Skarels fdp->fd_freefile = fd; 32815550Skarels *pf = 0; 329*47540Skarels 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 { 339*47540Skarels 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 349*47540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 350*47540Skarels (fp = OFILE(fdp, 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 /* 372*47540Skarels * Allocate a file descriptor for the process. 3737422Sroot */ 374*47540Skarels int fdexpand; 37545914Smckusick 376*47540Skarels fdalloc(p, want, result) 377*47540Skarels struct proc *p; 378*47540Skarels int want; 37937728Smckusick int *result; 3807422Sroot { 381*47540Skarels register struct filedesc *fdp = p->p_fd; 382*47540Skarels register int i; 383*47540Skarels int lim, last, nfiles; 38445914Smckusick struct file **newofile; 38545914Smckusick char *newofileflags; 3867497Sroot 387*47540Skarels /* 388*47540Skarels * Search for a free descriptor starting at the higher 389*47540Skarels * of want or fd_freefile. If that fails, consider 390*47540Skarels * expanding the ofile array. 391*47540Skarels */ 392*47540Skarels lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur; 39345914Smckusick for (;;) { 394*47540Skarels last = min(fdp->fd_nfiles, lim); 395*47540Skarels if ((i = want) < fdp->fd_freefile) 396*47540Skarels i = fdp->fd_freefile; 397*47540Skarels for (; i < last; i++) { 398*47540Skarels if (OFILE(fdp, i) == NULL) { 399*47540Skarels OFILEFLAGS(fdp, i) = 0; 400*47540Skarels if (i > fdp->fd_lastfile) 401*47540Skarels fdp->fd_lastfile = i; 402*47540Skarels if (fdp->fd_freefile <= want) 403*47540Skarels fdp->fd_freefile = i; 404*47540Skarels *result = i; 40545914Smckusick return (0); 40645914Smckusick } 4077497Sroot } 408*47540Skarels 409*47540Skarels /* 410*47540Skarels * No space in current array. Expand? 411*47540Skarels */ 412*47540Skarels if (fdp->fd_nfiles >= lim) 41345914Smckusick return (EMFILE); 414*47540Skarels nfiles = 2 * fdp->fd_nfiles; 415*47540Skarels MALLOC(newofile, struct file **, nfiles * OFILESIZE, 416*47540Skarels M_FILEDESC, M_WAITOK); 417*47540Skarels newofileflags = (char *) &newofile[nfiles]; 418*47540Skarels /* 419*47540Skarels * Copy the existing ofile and ofileflags arrays 420*47540Skarels * and zero the new portion of each array. 421*47540Skarels */ 422*47540Skarels bcopy(fdp->fd_ofiles, newofile, 423*47540Skarels (i = sizeof(struct file *) * fdp->fd_nfiles)); 424*47540Skarels bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i); 425*47540Skarels bcopy(fdp->fd_ofileflags, newofileflags, 426*47540Skarels (i = sizeof(char) * fdp->fd_nfiles)); 427*47540Skarels bzero(newofileflags + i, nfiles * sizeof(char) - i); 428*47540Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 429*47540Skarels fdp->fd_ofiles = newofile; 430*47540Skarels fdp->fd_ofileflags = newofileflags; 431*47540Skarels fdp->fd_nfiles = nfiles; 432*47540Skarels fdexpand++; 43339733Smckusick } 4347497Sroot } 4357497Sroot 43642863Smckusick /* 437*47540Skarels * Check to see whether n user file descriptors are available. 43842863Smckusick */ 439*47540Skarels fdavail(p, n) 440*47540Skarels struct proc *p; 441*47540Skarels register int n; 44212748Ssam { 443*47540Skarels register struct filedesc *fdp = p->p_fd; 444*47540Skarels register int i; 44512748Ssam 446*47540Skarels if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 && 447*47540Skarels (n -= i) <= 0) 448*47540Skarels return (1); 449*47540Skarels for (i = fdp->fd_freefile; i < fdp->fd_nfiles; i++) 450*47540Skarels if (OFILE(fdp, i) == NULL && --n <= 0) 451*47540Skarels return (1); 452*47540Skarels for (i = 0; i < fdp->fd_freefile; i++) 453*47540Skarels if (OFILE(fdp, i) == NULL && --n <= 0) 454*47540Skarels return (1); 455*47540Skarels return (0); 45612748Ssam } 45712748Ssam 4587497Sroot struct file *lastf; 4597497Sroot /* 460*47540Skarels * Create a new open file structure and allocate 461*47540Skarels * a file decriptor for the process that refers to it. 4627497Sroot */ 46345914Smckusick falloc(p, resultfp, resultfd) 46445914Smckusick register struct proc *p; 46537728Smckusick struct file **resultfp; 46637728Smckusick int *resultfd; 4677497Sroot { 4687422Sroot register struct file *fp; 46937728Smckusick int error, i; 4707422Sroot 471*47540Skarels if (error = fdalloc(p, 0, &i)) 47237728Smckusick return (error); 4737497Sroot if (lastf == 0) 4747497Sroot lastf = file; 4757497Sroot for (fp = lastf; fp < fileNFILE; fp++) 4767497Sroot if (fp->f_count == 0) 4777497Sroot goto slot; 4787497Sroot for (fp = file; fp < lastf; fp++) 4797497Sroot if (fp->f_count == 0) 4807497Sroot goto slot; 4817497Sroot tablefull("file"); 48237728Smckusick return (ENFILE); 4837497Sroot slot: 48445914Smckusick OFILE(p->p_fd, i) = fp; 48512748Ssam fp->f_count = 1; 48612748Ssam fp->f_data = 0; 4877497Sroot fp->f_offset = 0; 488*47540Skarels fp->f_cred = p->p_ucred; 48937728Smckusick crhold(fp->f_cred); 4907497Sroot lastf = fp + 1; 49137728Smckusick if (resultfp) 49237728Smckusick *resultfp = fp; 49337728Smckusick if (resultfd) 49437728Smckusick *resultfd = i; 49537728Smckusick return (0); 4967497Sroot } 49712748Ssam 4987497Sroot /* 499*47540Skarels * Copy a filedesc structure. 50045914Smckusick */ 50145914Smckusick struct filedesc * 502*47540Skarels fdcopy(p) 503*47540Skarels struct proc *p; 50445914Smckusick { 505*47540Skarels register struct filedesc *fdp = p->p_fd; 50645914Smckusick register struct filedesc *newfdp; 50745914Smckusick register struct file *fp; 50845914Smckusick register int i; 50945914Smckusick 510*47540Skarels MALLOC(newfdp, struct filedesc *, sizeof(*fdp), M_FILEDESC, M_WAITOK); 511*47540Skarels bcopy(fdp, newfdp, sizeof(*fdp)); 51245914Smckusick VREF(newfdp->fd_cdir); 51345914Smckusick if (newfdp->fd_rdir) 51445914Smckusick VREF(newfdp->fd_rdir); 51545914Smckusick newfdp->fd_refcnt = 1; 516*47540Skarels 517*47540Skarels /* 518*47540Skarels * Compute the smallest multiple of NOEXTENT needed 519*47540Skarels * for the file descriptors currently in use, 520*47540Skarels * allowing the table to shrink. 521*47540Skarels */ 522*47540Skarels i = newfdp->fd_nfiles; 523*47540Skarels while (i > NOEXTENT * 2 && i >= (fdp->fd_lastfile + 1) / 2) 524*47540Skarels i /= 2; 525*47540Skarels newfdp->fd_nfiles = i; 526*47540Skarels MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE, 527*47540Skarels M_FILEDESC, M_WAITOK); 528*47540Skarels newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; 529*47540Skarels bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **)); 530*47540Skarels bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char)); 531*47540Skarels for (i = 0; i <= newfdp->fd_lastfile; i++) 532*47540Skarels if (fp = OFILE(newfdp, i)) 533*47540Skarels fp->f_count++; 53445914Smckusick return (newfdp); 53545914Smckusick } 53645914Smckusick 53745914Smckusick /* 53845914Smckusick * Release a filedesc structure. 53945914Smckusick */ 540*47540Skarels fdfree(p) 541*47540Skarels struct proc *p; 54245914Smckusick { 543*47540Skarels register struct filedesc *fdp = p->p_fd; 544*47540Skarels struct file *fp; 54545914Smckusick register int i; 54645914Smckusick 547*47540Skarels if (--fdp->fd_refcnt > 0) 54845914Smckusick return; 549*47540Skarels for (i = 0; i <= fdp->fd_lastfile; i++) 550*47540Skarels if (fp = OFILE(fdp, i)) 551*47540Skarels (void) closef(fp, p); 552*47540Skarels FREE(fdp->fd_ofiles, M_FILEDESC); 55345914Smckusick vrele(fdp->fd_cdir); 55445914Smckusick if (fdp->fd_rdir) 55545914Smckusick vrele(fdp->fd_rdir); 556*47540Skarels FREE(fdp, M_FILEDESC); 55745914Smckusick } 55845914Smckusick 55945914Smckusick /* 5607497Sroot * Internal form of close. 56112748Ssam * Decrement reference count on file structure. 5627497Sroot */ 563*47540Skarels closef(fp, p) 5647497Sroot register struct file *fp; 565*47540Skarels struct proc *p; 5667497Sroot { 56746200Smckusick struct vnode *vp; 56846200Smckusick struct flock lf; 56939354Smckusick int error; 5707497Sroot 5717422Sroot if (fp == NULL) 57239354Smckusick return (0); 57346200Smckusick /* 57446200Smckusick * POSIX record locking dictates that any close releases ALL 57546200Smckusick * locks owned by this process. This is handled by setting 57646200Smckusick * a flag in the unlock to free ONLY locks obeying POSIX 57746200Smckusick * semantics, and not to free BSD-style file locks. 57846200Smckusick */ 57946200Smckusick if (fp->f_type == DTYPE_VNODE) { 58046200Smckusick lf.l_whence = SEEK_SET; 58146200Smckusick lf.l_start = 0; 58246200Smckusick lf.l_len = 0; 58346200Smckusick lf.l_type = F_UNLCK; 58446200Smckusick vp = (struct vnode *)fp->f_data; 58546200Smckusick (void) VOP_ADVLOCK(vp, p, F_UNLCK, &lf, F_POSIX); 58646200Smckusick } 587*47540Skarels if (--fp->f_count > 0) 58839354Smckusick return (0); 589*47540Skarels if (fp->f_count < 0) 590*47540Skarels panic("closef: count < 0"); 59146200Smckusick if (fp->f_type == DTYPE_VNODE) 59246200Smckusick (void) VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK); 59339354Smckusick error = (*fp->f_ops->fo_close)(fp); 59437728Smckusick crfree(fp->f_cred); 5957497Sroot fp->f_count = 0; 59639354Smckusick return (error); 5977422Sroot } 59813044Ssam 59913044Ssam /* 60013044Ssam * Apply an advisory lock on a file descriptor. 60146200Smckusick * 60246200Smckusick * Just attempt to get a record lock of the requested type on 60346200Smckusick * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). 60413044Ssam */ 60546200Smckusick 60642863Smckusick /* ARGSUSED */ 60742863Smckusick flock(p, uap, retval) 60842863Smckusick struct proc *p; 60942863Smckusick register struct args { 610*47540Skarels int fd; 61113044Ssam int how; 61242863Smckusick } *uap; 61342863Smckusick int *retval; 61442863Smckusick { 61545914Smckusick register struct filedesc *fdp = p->p_fd; 61613044Ssam register struct file *fp; 61746200Smckusick struct vnode *vp; 61846200Smckusick struct flock lf; 61946200Smckusick int error; 62013044Ssam 621*47540Skarels if ((unsigned)uap->fd >= fdp->fd_nfiles || 622*47540Skarels (fp = OFILE(fdp, uap->fd)) == NULL) 62344404Skarels return (EBADF); 62442863Smckusick if (fp->f_type != DTYPE_VNODE) 62544404Skarels return (EOPNOTSUPP); 62646200Smckusick vp = (struct vnode *)fp->f_data; 62746200Smckusick lf.l_whence = SEEK_SET; 62846200Smckusick lf.l_start = 0; 62946200Smckusick lf.l_len = 0; 63013101Ssam if (uap->how & LOCK_UN) { 63146200Smckusick lf.l_type = F_UNLCK; 63246200Smckusick return (VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK)); 63313044Ssam } 63417998Skarels if (uap->how & LOCK_EX) 63546200Smckusick lf.l_type = F_WRLCK; 63646200Smckusick else if (uap->how & LOCK_SH) 63746200Smckusick lf.l_type = F_RDLCK; 63846200Smckusick else 63946200Smckusick return (EBADF); 64046200Smckusick if (uap->how & LOCK_NB) 64146200Smckusick return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK)); 64246200Smckusick return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); 64313044Ssam } 64437586Smarc 64537586Smarc /* 64637586Smarc * File Descriptor pseudo-device driver (/dev/fd/). 64737586Smarc * 64837586Smarc * Opening minor device N dup()s the file (if any) connected to file 64937586Smarc * descriptor N belonging to the calling process. Note that this driver 65037586Smarc * consists of only the ``open()'' routine, because all subsequent 65137586Smarc * references to this file will be direct to the other driver. 65237586Smarc */ 65337728Smckusick /* ARGSUSED */ 65437728Smckusick fdopen(dev, mode, type) 65537586Smarc dev_t dev; 65637728Smckusick int mode, type; 65737586Smarc { 65837586Smarc 65937586Smarc /* 660*47540Skarels * XXX Kludge: set curproc->p_dupfd to contain the value of the 66143406Smckusick * the file descriptor being sought for duplication. The error 66243406Smckusick * return ensures that the vnode for this device will be released 66343406Smckusick * by vn_open. Open will detect this special error and take the 66443406Smckusick * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN 66543406Smckusick * will simply report the error. 66637586Smarc */ 667*47540Skarels curproc->p_dupfd = minor(dev); /* XXX */ 66843406Smckusick return (ENODEV); 66943406Smckusick } 67040873Sbostic 67143406Smckusick /* 67243406Smckusick * Duplicate the specified descriptor to a free descriptor. 67343406Smckusick */ 67445914Smckusick dupfdopen(fdp, indx, dfd, mode) 67545914Smckusick register struct filedesc *fdp; 67643406Smckusick register int indx, dfd; 67743406Smckusick int mode; 67843406Smckusick { 67943406Smckusick register struct file *wfp; 68043406Smckusick struct file *fp; 68143406Smckusick 68237586Smarc /* 68343406Smckusick * If the to-be-dup'd fd number is greater than the allowed number 68443406Smckusick * of file descriptors, or the fd to be dup'd has already been 68543406Smckusick * closed, reject. Note, check for new == old is necessary as 68643406Smckusick * falloc could allocate an already closed to-be-dup'd descriptor 68743406Smckusick * as the new descriptor. 68837586Smarc */ 68945914Smckusick fp = OFILE(fdp, indx); 690*47540Skarels if ((u_int)dfd >= fdp->fd_nfiles || (wfp = OFILE(fdp, dfd)) == NULL || 69140873Sbostic fp == wfp) 69237586Smarc return (EBADF); 69340873Sbostic 69437586Smarc /* 69540873Sbostic * Check that the mode the file is being opened for is a subset 69640873Sbostic * of the mode of the existing descriptor. 69737586Smarc */ 69843406Smckusick if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) 69937586Smarc return (EACCES); 70045914Smckusick OFILE(fdp, indx) = wfp; 70145914Smckusick OFILEFLAGS(fdp, indx) = OFILEFLAGS(fdp, dfd); 70242863Smckusick wfp->f_count++; 70345914Smckusick if (indx > fdp->fd_lastfile) 70445914Smckusick fdp->fd_lastfile = indx; 70543406Smckusick return (0); 70637586Smarc } 707