X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/ea795ba9929f321bc07afa1303d42ffccfa8753e..8429d0227448605965610a9e25ac573e07e17507:/usr/src/sys/kern/kern_descrip.c diff --git a/usr/src/sys/kern/kern_descrip.c b/usr/src/sys/kern/kern_descrip.c index 9d8ec10dc6..22d0bf3f5a 100644 --- a/usr/src/sys/kern/kern_descrip.c +++ b/usr/src/sys/kern/kern_descrip.c @@ -1,412 +1,475 @@ -/* kern_descrip.c 5.15 82/10/22 */ - -#include "../h/param.h" -#include "../h/systm.h" -#include "../h/dir.h" -#include "../h/user.h" -#include "../h/kernel.h" -#include "../h/inode.h" -#include "../h/proc.h" -#include "../h/conf.h" -#include "../h/file.h" -#include "../h/socket.h" -#include "../h/socketvar.h" -#include "../h/mount.h" - -#include "../h/descrip.h" - /* - * Descriptor management. + * Copyright (c) 1982, 1986, 1989 Regents of the University of California. + * All rights reserved. + * + * %sccs.include.redist.c% + * + * @(#)kern_descrip.c 7.21 (Berkeley) %G% */ +#include "param.h" +#include "systm.h" +#include "user.h" +#include "filedesc.h" +#include "kernel.h" +#include "vnode.h" +#include "proc.h" +#include "file.h" +#include "socket.h" +#include "socketvar.h" +#include "stat.h" +#include "ioctl.h" +#include "fcntl.h" +#include "malloc.h" +#include "syslog.h" + /* - * TODO: - * getf should be renamed - * ufalloc side effects are gross + * Descriptor management. */ /* * System calls on descriptors. */ -getdtablesize() +/* ARGSUSED */ +getdtablesize(p, uap, retval) + struct proc *p; + struct args *uap; + int *retval; { - u.u_r.r_val1 = NOFILE; + *retval = p->p_rlimit[RLIMIT_OFILE].rlim_cur; + return (0); +} + +/* + * Duplicate a file descriptor. + */ +/* ARGSUSED */ +dup(p, uap, retval) + struct proc *p; + struct args { + int i; + } *uap; + int *retval; +{ + register struct filedesc *fdp = p->p_fd; + struct file *fp; + int fd, error; + + /* + * XXX Compatibility + */ + if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); } + + if ((unsigned)uap->i >= fdp->fd_nfiles || + (fp = OFILE(fdp, uap->i)) == NULL) + return (EBADF); + if (error = fdalloc(p, 0, &fd)) + return (error); + OFILE(fdp, fd) = fp; + OFILEFLAGS(fdp, fd) = OFILEFLAGS(fdp, uap->i) &~ UF_EXCLOSE; + fp->f_count++; + if (fd > fdp->fd_lastfile) + fdp->fd_lastfile = fd; + *retval = fd; + return (0); } -getdprop() +/* + * Duplicate a file descriptor to a particular value. + */ +/* ARGSUSED */ +dup2(p, uap, retval) + struct proc *p; + register struct args { + int i; + int j; + } *uap; + int *retval; { - register struct a { - int d; - struct dtype *dtypeb; - } *uap = (struct a *)u.u_ap; + register struct filedesc *fdp = p->p_fd; register struct file *fp; - struct dtype adtype; + int i, error; - fp = getf(uap->d); - if (fp == 0) - return; - adtype.dt_type = 0; /* XXX */ - adtype.dt_protocol = 0; /* XXX */ - if (copyout((caddr_t)&adtype, (caddr_t)uap->dtypeb, - sizeof (struct dtype)) < 0) { - u.u_error = EFAULT; - return; + if ((unsigned)uap->i >= fdp->fd_nfiles || + (fp = OFILE(fdp, uap->i)) == NULL || + (unsigned)uap->j >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) + return (EBADF); + *retval = uap->j; + if (uap->i == uap->j) + return (0); + if ((unsigned)uap->j >= fdp->fd_nfiles) { + if (error = fdalloc(p, uap->j, &i)) + return (error); + if (uap->j != i) + panic("dup2: fdalloc"); + } else if (OFILE(fdp, uap->j)) { + if (OFILEFLAGS(fdp, uap->j) & UF_MAPPED) + (void) munmapfd(p, uap->j); + error = closef(OFILE(fdp, uap->j), p); } + OFILE(fdp, uap->j) = fp; + OFILEFLAGS(fdp, uap->j) = OFILEFLAGS(fdp, uap->i) &~ UF_EXCLOSE; + fp->f_count++; + if (uap->j > fdp->fd_lastfile) + fdp->fd_lastfile = uap->j; + /* + * dup2() must succeed even though the close had an error. + */ + error = 0; /* XXX */ + return (error); } -getdopt() +/* + * The file control system call. + */ +/* ARGSUSED */ +fcntl(p, uap, retval) + struct proc *p; + register struct args { + int fd; + int cmd; + int arg; + } *uap; + int *retval; { + register struct filedesc *fdp = p->p_fd; + register struct file *fp; + register char *pop; + struct vnode *vp; + int i, error, flags = F_POSIX; + struct flock fl; + + if ((unsigned)uap->fd >= fdp->fd_nfiles || + (fp = OFILE(fdp, uap->fd)) == NULL) + return (EBADF); + pop = &OFILEFLAGS(fdp, uap->fd); + switch(uap->cmd) { + case F_DUPFD: + if ((unsigned)uap->arg >= p->p_rlimit[RLIMIT_OFILE].rlim_cur) + return (EINVAL); + if (error = fdalloc(p, uap->arg, &i)) + return (error); + OFILE(fdp, i) = fp; + OFILEFLAGS(fdp, i) = *pop &~ UF_EXCLOSE; + fp->f_count++; + if (i > fdp->fd_lastfile) + fdp->fd_lastfile = i; + *retval = i; + return (0); + + case F_GETFD: + *retval = *pop & 1; + return (0); + + case F_SETFD: + *pop = (*pop &~ 1) | (uap->arg & 1); + return (0); + + case F_GETFL: + *retval = OFLAGS(fp->f_flag); + return (0); + + case F_SETFL: + fp->f_flag &= ~FCNTLFLAGS; + fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS; + if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY)) + return (error); + if (error = fset(fp, FASYNC, fp->f_flag & FASYNC)) + (void) fset(fp, FNDELAY, 0); + return (error); + + case F_GETOWN: + return (fgetown(fp, retval)); + + case F_SETOWN: + return (fsetown(fp, uap->arg)); + + case F_SETLKW: + flags |= F_WAIT; + /* Fall into F_SETLK */ + + case F_SETLK: + if (fp->f_type != DTYPE_VNODE) + return (EBADF); + vp = (struct vnode *)fp->f_data; + /* Copy in the lock structure */ + error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); + if (error) + return (error); + if (fl.l_whence == SEEK_CUR) + fl.l_start += fp->f_offset; + switch (fl.l_type) { + + case F_RDLCK: + if ((fp->f_flag & FREAD) == 0) + return (EBADF); + return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags)); + + case F_WRLCK: + if ((fp->f_flag & FWRITE) == 0) + return (EBADF); + return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags)); + + case F_UNLCK: + return (VOP_ADVLOCK(vp, p, F_UNLCK, &fl, F_POSIX)); + + default: + return (EINVAL); + } + case F_GETLK: + if (fp->f_type != DTYPE_VNODE) + return (EBADF); + vp = (struct vnode *)fp->f_data; + /* Copy in the lock structure */ + error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl)); + if (error) + return (error); + if (fl.l_whence == SEEK_CUR) + fl.l_start += fp->f_offset; + if (error = VOP_ADVLOCK(vp, p, F_GETLK, &fl, F_POSIX)) + return (error); + return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl))); + + default: + return (EINVAL); + } + /* NOTREACHED */ } -setdopt() +fset(fp, bit, value) + struct file *fp; + int bit, value; { + if (value) + fp->f_flag |= bit; + else + fp->f_flag &= ~bit; + return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC), + (caddr_t)&value)); } -dup() -{ - register struct a { - int i; - } *uap = (struct a *) u.u_ap; +fgetown(fp, valuep) struct file *fp; - int j; - - if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */ + int *valuep; +{ + int error; - fp = getf(uap->i); - if (fp == 0) - return; - j = ufalloc(); - if (j < 0) - return; - dupit(j, fp, u.u_pofile[uap->i] & (RDLOCK|WRLOCK)); -} + switch (fp->f_type) { -dup2() -{ - register struct a { - int i, j; - } *uap = (struct a *) u.u_ap; - register struct file *fp; + case DTYPE_SOCKET: + *valuep = ((struct socket *)fp->f_data)->so_pgid; + return (0); - fp = getf(uap->i); - if (fp == 0) - return; - if (uap->j < 0 || uap->j >= NOFILE) { - u.u_error = EBADF; - return; - } - u.u_r.r_val1 = uap->j; - if (uap->i == uap->j) - return; - if (u.u_ofile[uap->j]) { - closef(u.u_ofile[uap->j], 0, u.u_pofile[uap->j]); - if (u.u_error) - return; - /* u.u_ofile[uap->j] = 0; */ - /* u.u_pofile[uap->j] = 0; */ + default: + error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep); + *valuep = -*valuep; + return (error); } - dupit(uap->j, fp, u.u_pofile[uap->i] & (RDLOCK|WRLOCK)); } -dupit(fd, fp, lockflags) - int fd; - register struct file *fp; - register int lockflags; +fsetown(fp, value) + struct file *fp; + int value; { - u.u_ofile[fd] = fp; - u.u_pofile[fd] = lockflags; - fp->f_count++; - if (lockflags&RDLOCK) - fp->f_inode->i_rdlockc++; - if (lockflags&WRLOCK) - fp->f_inode->i_wrlockc++; + if (fp->f_type == DTYPE_SOCKET) { + ((struct socket *)fp->f_data)->so_pgid = value; + return (0); + } + if (value > 0) { + struct proc *p = pfind(value); + if (p == 0) + return (ESRCH); + value = p->p_pgrp->pg_id; + } else + value = -value; + return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value)); } -close() +fioctl(fp, cmd, value) + struct file *fp; + int cmd; + caddr_t value; { - register struct a { - int i; - } *uap = (struct a *)u.u_ap; - register struct file *fp; - fp = getf(uap->i); - if (fp == 0) - return; - closef(fp, 0, u.u_pofile[uap->i]); - /* WHAT IF u.u_error ? */ - u.u_ofile[uap->i] = NULL; - u.u_pofile[uap->i] = 0; + return ((*fp->f_ops->fo_ioctl)(fp, cmd, value)); } -wrap() +/* + * Close a file descriptor. + */ +/* ARGSUSED */ +close(p, uap, retval) + struct proc *p; + struct args { + int fd; + } *uap; + int *retval; { - register struct a { - int d; - struct dtype *dtypeb; - } *uap = (struct a *)u.u_ap; + register struct filedesc *fdp = p->p_fd; register struct file *fp; - struct dtype adtype; - - fp = getf(uap->d); - if (fp == 0) - return; - if (copyin((caddr_t)uap->dtypeb, (caddr_t)&adtype, - sizeof (struct dtype)) < 0) { - u.u_error = EFAULT; - return; - } - /* DO WRAP */ + register int fd = uap->fd; + register u_char *pf; + + if ((unsigned)fd >= fdp->fd_nfiles || + (fp = OFILE(fdp, fd)) == NULL) + return (EBADF); + pf = (u_char *)&OFILEFLAGS(fdp, fd); + if (*pf & UF_MAPPED) + (void) munmapfd(p, fd); + OFILE(fdp, fd) = NULL; + while (fdp->fd_lastfile >= 0 && OFILE(fdp, fdp->fd_lastfile) == NULL) + fdp->fd_lastfile--; + if (fd < fdp->fd_freefile) + fdp->fd_freefile = fd; + *pf = 0; + return (closef(fp, p)); } -int unselect(); -int nselcoll; /* - * Select system call. + * Return status information about a file descriptor. */ -select() +/* ARGSUSED */ +fstat(p, uap, retval) + struct proc *p; + register struct args { + int fd; + struct stat *sb; + } *uap; + int *retval; { - register struct uap { - int nd; - long *in; - long *ou; - long *ex; - struct timeval *tv; - } *uap = (struct uap *)u.u_ap; - int ibits[3], obits[3]; - struct timeval atv; - int s, ncoll; - label_t lqsave; - - obits[0] = obits[1] = obits[2] = 0; - if (uap->nd >= NOFILE) { - u.u_error = EINVAL; - goto done; - } - -#define getbits(name, x) \ - if (uap->name) { \ - if (copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \ - sizeof (ibits[x]))) { \ - u.u_error = EFAULT; \ - goto done; \ - } \ - } else \ - ibits[x] = 0; - getbits(in, 0); - getbits(ou, 1); - getbits(ex, 2); -#undef getbits - - if (uap->tv) { - if (copyin((caddr_t)uap->tv, (caddr_t)&atv, sizeof (atv))) { - u.u_error = EFAULT; - goto done; - } - if (itimerfix(&atv)) { - u.u_error = EINVAL; - goto done; - } - s = spl7(); timevaladd(&atv, &time); splx(s); - } -retry: - ncoll = nselcoll; - u.u_procp->p_flag |= SSEL; - u.u_r.r_val1 = selscan(ibits, obits); - if (u.u_error || u.u_r.r_val1) - goto done; - s = spl6(); - if (uap->tv && timercmp(&time, &atv, >=)) { - splx(s); - goto done; - } - if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) { - u.u_procp->p_flag &= ~SSEL; - splx(s); - goto retry; - } - u.u_procp->p_flag &= ~SSEL; - if (uap->tv) { - lqsave = u.u_qsave; - if (setjmp(&u.u_qsave)) { - untimeout(unselect, (caddr_t)u.u_procp); - u.u_error = EINTR; - splx(s); - goto done; - } - timeout(unselect, (caddr_t)u.u_procp, hzto(&atv)); - } - sleep((caddr_t)&selwait, PZERO+1); - if (uap->tv) { - u.u_qsave = lqsave; - untimeout(unselect, (caddr_t)u.u_procp); - } - splx(s); - goto retry; -done: -#define putbits(name, x) \ - if (uap->name) { \ - if (copyout((caddr_t)obits[x], (caddr_t)uap->name, \ - sizeof (obits[x]))) \ - u.u_error = EFAULT; \ - } - putbits(in, 0); - putbits(ou, 1); - putbits(ex, 2); -#undef putbits -} - -unselect(p) - register struct proc *p; -{ - register int s = spl6(); + register struct filedesc *fdp = p->p_fd; + register struct file *fp; + struct stat ub; + int error; - switch (p->p_stat) { + if ((unsigned)uap->fd >= fdp->fd_nfiles || + (fp = OFILE(fdp, uap->fd)) == NULL) + return (EBADF); + switch (fp->f_type) { - case SSLEEP: - setrun(p); + case DTYPE_VNODE: + error = vn_stat((struct vnode *)fp->f_data, &ub); break; - case SSTOP: - unsleep(p); + case DTYPE_SOCKET: + error = soo_stat((struct socket *)fp->f_data, &ub); break; - } - splx(s); -} - -selscan(ibits, obits) - int *ibits, *obits; -{ - register int which, bits, i; - int flag; - struct file *fp; - int able; - struct inode *ip; - int n = 0; - - for (which = 0; which < 3; which++) { - bits = ibits[which]; - obits[which] = 0; - switch (which) { - - case 0: - flag = FREAD; break; - - case 1: - flag = FWRITE; break; - - case 2: - flag = 0; break; - } - while (i = ffs(bits)) { - bits &= ~(1<<(i-1)); - fp = u.u_ofile[i-1]; - if (fp == NULL) { - u.u_error = EBADF; - break; - } - if (fp->f_type == DTYPE_SOCKET) - able = soselect(fp->f_socket, flag); - else { - ip = fp->f_inode; - switch (ip->i_mode & IFMT) { - - case IFCHR: - able = - (*cdevsw[major(ip->i_rdev)].d_select) - (ip->i_rdev, flag); - break; - - case IFBLK: - case IFREG: - case IFDIR: - able = 1; - break; - } - } - if (able) { - obits[which] |= (1<<(i-1)); - n++; - } - } + default: + panic("fstat"); + /*NOTREACHED*/ } - return (n); + if (error == 0) + error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub)); + return (error); } -/*ARGSUSED*/ -seltrue(dev, flag) - dev_t dev; - int flag; -{ - - return (1); -} +/* + * Allocate a file descriptor for the process. + */ +int fdexpand; -selwakeup(p, coll) - register struct proc *p; - int coll; +fdalloc(p, want, result) + struct proc *p; + int want; + int *result; { - int s; - - if (coll) { - nselcoll++; - wakeup((caddr_t)&selwait); - } - if (p) { - if (p->p_wchan == (caddr_t)&selwait) - setrun(p); - else { - s = spl6(); - if (p->p_flag & SSEL) - p->p_flag &= ~SSEL; - splx(s); + register struct filedesc *fdp = p->p_fd; + register int i; + int lim, last, nfiles; + struct file **newofile; + char *newofileflags; + + /* + * Search for a free descriptor starting at the higher + * of want or fd_freefile. If that fails, consider + * expanding the ofile array. + */ + lim = p->p_rlimit[RLIMIT_OFILE].rlim_cur; + for (;;) { + last = min(fdp->fd_nfiles, lim); + if ((i = want) < fdp->fd_freefile) + i = fdp->fd_freefile; + for (; i < last; i++) { + if (OFILE(fdp, i) == NULL) { + OFILEFLAGS(fdp, i) = 0; + if (i > fdp->fd_lastfile) + fdp->fd_lastfile = i; + if (fdp->fd_freefile <= want) + fdp->fd_freefile = i; + *result = i; + return (0); + } } - } -} - -revoke() -{ - /* XXX */ + /* + * No space in current array. Expand? + */ + if (fdp->fd_nfiles >= lim) + return (EMFILE); + nfiles = 2 * fdp->fd_nfiles; + MALLOC(newofile, struct file **, nfiles * OFILESIZE, + M_FILEDESC, M_WAITOK); + newofileflags = (char *) &newofile[nfiles]; + /* + * Copy the existing ofile and ofileflags arrays + * and zero the new portion of each array. + */ + bcopy(fdp->fd_ofiles, newofile, + (i = sizeof(struct file *) * fdp->fd_nfiles)); + bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i); + bcopy(fdp->fd_ofileflags, newofileflags, + (i = sizeof(char) * fdp->fd_nfiles)); + bzero(newofileflags + i, nfiles * sizeof(char) - i); + FREE(fdp->fd_ofiles, M_FILEDESC); + fdp->fd_ofiles = newofile; + fdp->fd_ofileflags = newofileflags; + fdp->fd_nfiles = nfiles; + fdexpand++; + } } /* - * Allocate a user file descriptor. + * Check to see whether n user file descriptors are available. */ -ufalloc() +fdavail(p, n) + struct proc *p; + register int n; { - register i; - - for (i=0; ip_fd; + register int i; + + if ((i = p->p_rlimit[RLIMIT_OFILE].rlim_cur - fdp->fd_nfiles) > 0 && + (n -= i) <= 0) + return (1); + for (i = fdp->fd_freefile; i < fdp->fd_nfiles; i++) + if (OFILE(fdp, i) == NULL && --n <= 0) + return (1); + for (i = 0; i < fdp->fd_freefile; i++) + if (OFILE(fdp, i) == NULL && --n <= 0) + return (1); + return (0); } struct file *lastf; /* - * Allocate a user file descriptor - * and a file structure. - * Initialize the descriptor - * to point at the file structure. + * Create a new open file structure and allocate + * a file decriptor for the process that refers to it. */ -struct file * -falloc() +falloc(p, resultfp, resultfd) + register struct proc *p; + struct file **resultfp; + int *resultfd; { register struct file *fp; - register i; + int error, i; - i = ufalloc(); - if (i < 0) - return (NULL); + if (error = fdalloc(p, 0, &i)) + return (error); if (lastf == 0) lastf = file; for (fp = lastf; fp < fileNFILE; fp++) @@ -416,124 +479,228 @@ falloc() if (fp->f_count == 0) goto slot; tablefull("file"); - u.u_error = ENFILE; - return (NULL); + return (ENFILE); slot: - u.u_ofile[i] = fp; - fp->f_count++; + OFILE(p->p_fd, i) = fp; + fp->f_count = 1; + fp->f_data = 0; fp->f_offset = 0; - fp->f_inode = 0; + fp->f_cred = p->p_ucred; + crhold(fp->f_cred); lastf = fp + 1; - return (fp); + if (resultfp) + *resultfp = fp; + if (resultfd) + *resultfd = i; + return (0); } + /* - * Convert a user supplied file descriptor into a pointer - * to a file structure. Only task is to check range of the descriptor. - * Critical paths should use the GETF macro, defined in inline.h. + * Copy a filedesc structure. */ -struct file * -getf(f) - register int f; +struct filedesc * +fdcopy(p) + struct proc *p; { + register struct filedesc *fdp = p->p_fd; + register struct filedesc *newfdp; register struct file *fp; + register int i; + + MALLOC(newfdp, struct filedesc *, sizeof(*fdp), M_FILEDESC, M_WAITOK); + bcopy(fdp, newfdp, sizeof(*fdp)); + VREF(newfdp->fd_cdir); + if (newfdp->fd_rdir) + VREF(newfdp->fd_rdir); + newfdp->fd_refcnt = 1; + + /* + * Compute the smallest multiple of NOEXTENT needed + * for the file descriptors currently in use, + * allowing the table to shrink. + */ + i = newfdp->fd_nfiles; + while (i > NOEXTENT * 2 && i >= (fdp->fd_lastfile + 1) / 2) + i /= 2; + newfdp->fd_nfiles = i; + MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE, + M_FILEDESC, M_WAITOK); + newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; + bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **)); + bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char)); + for (i = 0; i <= newfdp->fd_lastfile; i++) + if (fp = OFILE(newfdp, i)) + fp->f_count++; + return (newfdp); +} - if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) { - u.u_error = EBADF; - return (NULL); - } - return (fp); +/* + * Release a filedesc structure. + */ +fdfree(p) + struct proc *p; +{ + register struct filedesc *fdp = p->p_fd; + struct file *fp; + register int i; + + if (--fdp->fd_refcnt > 0) + return; + for (i = 0; i <= fdp->fd_lastfile; i++) + if (fp = OFILE(fdp, i)) + (void) closef(fp, p); + FREE(fdp->fd_ofiles, M_FILEDESC); + vrele(fdp->fd_cdir); + if (fdp->fd_rdir) + vrele(fdp->fd_rdir); + FREE(fdp, M_FILEDESC); } /* * Internal form of close. - * Decrement reference count on - * file structure. - * Also make sure the pipe protocol - * does not constipate. - * - * Decrement reference count on the inode following - * removal to the referencing file structure. - * Call device handler on last close. - * Nouser indicates that the user isn't available to present - * errors to. - * - * Handling locking at this level is RIDICULOUS. + * Decrement reference count on file structure. */ -closef(fp, nouser, flags) +closef(fp, p) register struct file *fp; - int nouser, flags; + struct proc *p; { - register struct inode *ip; - register struct mount *mp; - int flag, mode; - dev_t dev; - register int (*cfunc)(); + struct vnode *vp; + struct flock lf; + int error; if (fp == NULL) - return; - if (fp->f_count > 1) { - fp->f_count--; - return; - } - if (fp->f_type == DTYPE_SOCKET) { - u.u_error = soclose(fp->f_socket, nouser); - if (nouser == 0 && u.u_error) - return; - fp->f_socket = 0; - fp->f_count = 0; - return; + return (0); + /* + * POSIX record locking dictates that any close releases ALL + * locks owned by this process. This is handled by setting + * a flag in the unlock to free ONLY locks obeying POSIX + * semantics, and not to free BSD-style file locks. + */ + if (fp->f_type == DTYPE_VNODE) { + lf.l_whence = SEEK_SET; + lf.l_start = 0; + lf.l_len = 0; + lf.l_type = F_UNLCK; + vp = (struct vnode *)fp->f_data; + (void) VOP_ADVLOCK(vp, p, F_UNLCK, &lf, F_POSIX); } - flag = fp->f_flag; - ip = fp->f_inode; - dev = (dev_t)ip->i_rdev; - mode = ip->i_mode & IFMT; - flags &= RDLOCK|WRLOCK; /* conservative */ - if (flags) - funlocki(ip, flags); - ilock(ip); - iput(ip); + if (--fp->f_count > 0) + return (0); + if (fp->f_count < 0) + panic("closef: count < 0"); + if (fp->f_type == DTYPE_VNODE) + (void) VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK); + error = (*fp->f_ops->fo_close)(fp); + crfree(fp->f_cred); fp->f_count = 0; + return (error); +} - switch (mode) { - - case IFCHR: - cfunc = cdevsw[major(dev)].d_close; - break; - - case IFBLK: - /* - * We don't want to really close the device if it is mounted - */ - for (mp = mount; mp < &mount[NMOUNT]; mp++) - if (mp->m_bufp != NULL && mp->m_dev == dev) - return; - cfunc = bdevsw[major(dev)].d_close; - break; +/* + * Apply an advisory lock on a file descriptor. + * + * Just attempt to get a record lock of the requested type on + * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). + */ - default: - return; - } - for (fp = file; fp < fileNFILE; fp++) { - if (fp->f_type == DTYPE_SOCKET) /* XXX */ - continue; - if (fp->f_count && (ip = fp->f_inode) && - ip->i_rdev == dev && (ip->i_mode&IFMT) == mode) - return; - } - if (mode == IFBLK) { - /* - * On last close of a block device (that isn't mounted) - * we must invalidate any in core blocks - */ - bflush(dev); - binval(dev); +/* ARGSUSED */ +flock(p, uap, retval) + struct proc *p; + register struct args { + int fd; + int how; + } *uap; + int *retval; +{ + register struct filedesc *fdp = p->p_fd; + register struct file *fp; + struct vnode *vp; + struct flock lf; + int error; + + if ((unsigned)uap->fd >= fdp->fd_nfiles || + (fp = OFILE(fdp, uap->fd)) == NULL) + return (EBADF); + if (fp->f_type != DTYPE_VNODE) + return (EOPNOTSUPP); + vp = (struct vnode *)fp->f_data; + lf.l_whence = SEEK_SET; + lf.l_start = 0; + lf.l_len = 0; + if (uap->how & LOCK_UN) { + lf.l_type = F_UNLCK; + return (VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK)); } - (*cfunc)(dev, flag, fp); + if (uap->how & LOCK_EX) + lf.l_type = F_WRLCK; + else if (uap->how & LOCK_SH) + lf.l_type = F_RDLCK; + else + return (EBADF); + if (uap->how & LOCK_NB) + return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK)); + return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); } -opause() +/* + * File Descriptor pseudo-device driver (/dev/fd/). + * + * Opening minor device N dup()s the file (if any) connected to file + * descriptor N belonging to the calling process. Note that this driver + * consists of only the ``open()'' routine, because all subsequent + * references to this file will be direct to the other driver. + */ +/* ARGSUSED */ +fdopen(dev, mode, type) + dev_t dev; + int mode, type; { - for (;;) - sleep((caddr_t)&u, PSLEP); + /* + * XXX Kludge: set curproc->p_dupfd to contain the value of the + * the file descriptor being sought for duplication. The error + * return ensures that the vnode for this device will be released + * by vn_open. Open will detect this special error and take the + * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN + * will simply report the error. + */ + curproc->p_dupfd = minor(dev); /* XXX */ + return (ENODEV); +} + +/* + * Duplicate the specified descriptor to a free descriptor. + */ +dupfdopen(fdp, indx, dfd, mode) + register struct filedesc *fdp; + register int indx, dfd; + int mode; +{ + register struct file *wfp; + struct file *fp; + + /* + * If the to-be-dup'd fd number is greater than the allowed number + * of file descriptors, or the fd to be dup'd has already been + * closed, reject. Note, check for new == old is necessary as + * falloc could allocate an already closed to-be-dup'd descriptor + * as the new descriptor. + */ + fp = OFILE(fdp, indx); + if ((u_int)dfd >= fdp->fd_nfiles || (wfp = OFILE(fdp, dfd)) == NULL || + fp == wfp) + return (EBADF); + + /* + * Check that the mode the file is being opened for is a subset + * of the mode of the existing descriptor. + */ + if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) + return (EACCES); + OFILE(fdp, indx) = wfp; + OFILEFLAGS(fdp, indx) = OFILEFLAGS(fdp, dfd); + wfp->f_count++; + if (indx > fdp->fd_lastfile) + fdp->fd_lastfile = indx; + return (0); }