X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/b32450f463002a07ee0e7581a231c6916a24a5d7..a937f8567ba9375553a85507f18042a6faaffaab:/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 928392e57c..769d23d4d0 100644 --- a/usr/src/sys/kern/kern_descrip.c +++ b/usr/src/sys/kern/kern_descrip.c @@ -1,28 +1,38 @@ -/* kern_descrip.c 5.13 82/10/17 */ - -#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. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)kern_descrip.c 7.4 (Berkeley) %G% */ +#include "param.h" +#include "systm.h" +#include "syscontext.h" +#include "kernel.h" +#include "vnode.h" +#include "proc.h" +#include "file.h" +#include "socket.h" +#include "socketvar.h" +#include "mount.h" +#include "stat.h" + +#include "ioctl.h" + /* - * TODO: - * getf should be renamed - * ufalloc side effects are gross + * Descriptor management. */ /* @@ -34,37 +44,6 @@ getdtablesize() u.u_r.r_val1 = NOFILE; } -getdprop() -{ - register struct a { - int d; - struct dtype *dtypeb; - } *uap = (struct a *)u.u_ap; - register struct file *fp; - struct dtype adtype; - - 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; - } -} - -getdopt() -{ - -} - -setdopt() -{ - -} - dup() { register struct a { @@ -75,13 +54,12 @@ dup() if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */ - fp = getf(uap->i); - if (fp == 0) + if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) + RETURN (EBADF); + if (u.u_error = ufalloc(0, &j)) return; - j = ufalloc(); - if (j < 0) - return; - dupit(j, fp, u.u_pofile[uap->i] & (RDLOCK|WRLOCK)); + u.u_r.r_val1 = j; + dupit(j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); } dup2() @@ -91,9 +69,8 @@ dup2() } *uap = (struct a *) u.u_ap; register struct file *fp; - fp = getf(uap->i); - if (fp == 0) - return; + if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL) + RETURN (EBADF); if (uap->j < 0 || uap->j >= NOFILE) { u.u_error = EBADF; return; @@ -102,296 +79,235 @@ dup2() 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_pofile[uap->j] & UF_MAPPED) + munmapfd(uap->j); + closef(u.u_ofile[uap->j]); if (u.u_error) return; - /* u.u_ofile[uap->j] = 0; */ - /* u.u_pofile[uap->j] = 0; */ } - dupit(uap->j, fp, u.u_pofile[uap->i] & (RDLOCK|WRLOCK)); + dupit(uap->j, fp, u.u_pofile[uap->i] &~ UF_EXCLOSE); } -dupit(fd, fp, lockflags) +dupit(fd, fp, flags) int fd; register struct file *fp; - register int lockflags; + register int flags; { u.u_ofile[fd] = fp; - u.u_pofile[fd] = lockflags; + u.u_pofile[fd] = flags; fp->f_count++; - if (lockflags&RDLOCK) - fp->f_inode->i_rdlockc++; - if (lockflags&WRLOCK) - fp->f_inode->i_wrlockc++; + if (fd > u.u_lastfile) + u.u_lastfile = fd; } -close() +/* + * The file control system call. + */ +fcntl() { - 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; -} - -wrap() -{ register struct a { - int d; - struct dtype *dtypeb; + int fdes; + int cmd; + int arg; } *uap = (struct a *)u.u_ap; - 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 */ -} - -int unselect(); -int nselcoll; -/* - * Select system call. - */ -select() -{ - 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; - - if (uap->nd >= NOFILE) { - u.u_error = EINVAL; - return; - } - -#define getbits(name, x) \ - if (uap->name) { \ - if (copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \ - sizeof (ibits[x]))) { \ - u.u_error = EFAULT; \ - return; \ - } \ - } 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; - return; - } - if (itimerfix(&atv)) { + register char *pop; + int i; + + if ((unsigned)uap->fdes >= NOFILE || + (fp = u.u_ofile[uap->fdes]) == NULL) + RETURN (EBADF); + pop = &u.u_pofile[uap->fdes]; + switch(uap->cmd) { + case F_DUPFD: + if (uap->arg < 0 || uap->arg >= NOFILE) { u.u_error = EINVAL; return; } - 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) - return; - if (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); + if (u.u_error = ufalloc(uap->arg, &i)) return; - } - 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; \ - return; \ - } \ - } - putbits(in, 0); - putbits(ou, 1); - putbits(ex, 2); -#undef putbits -} + u.u_r.r_val1 = i; + dupit(i, fp, *pop &~ UF_EXCLOSE); + break; -unselect(p) - register struct proc *p; -{ - register int s = spl6(); + case F_GETFD: + u.u_r.r_val1 = *pop & 1; + break; - switch (p->p_stat) { + case F_SETFD: + *pop = (*pop &~ 1) | (uap->arg & 1); + break; - case SSLEEP: - setrun(p); + case F_GETFL: + u.u_r.r_val1 = fp->f_flag+FOPEN; break; - case SSTOP: - unsleep(p); + case F_SETFL: + fp->f_flag &= FCNTLCANT; + fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT; + u.u_error = fset(fp, FNDELAY, fp->f_flag & FNDELAY); + if (u.u_error) + break; + u.u_error = fset(fp, FASYNC, fp->f_flag & FASYNC); + if (u.u_error) + (void) fset(fp, FNDELAY, 0); break; + + case F_GETOWN: + u.u_error = fgetown(fp, &u.u_r.r_val1); + break; + + case F_SETOWN: + u.u_error = fsetown(fp, uap->arg); + break; + + default: + u.u_error = EINVAL; } - splx(s); } -selscan(ibits, obits) - int *ibits, *obits; -{ - register int which, bits, i; - int flag; +fset(fp, bit, value) struct file *fp; - int able; - struct inode *ip; - int n = 0; + int bit, value; +{ - for (which = 0; which < 3; which++) { - bits = ibits[which]; - obits[which] = 0; - switch (which) { + if (value) + fp->f_flag |= bit; + else + fp->f_flag &= ~bit; + return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC), + (caddr_t)&value)); +} + +fgetown(fp, valuep) + struct file *fp; + int *valuep; +{ + int error; - case 0: - flag = FREAD; break; + switch (fp->f_type) { - case 1: - flag = FWRITE; break; + case DTYPE_SOCKET: + *valuep = ((struct socket *)fp->f_data)->so_pgid; + return (0); - 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: + error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep); + *valuep = -*valuep; + return (error); } - return (n); } -/*ARGSUSED*/ -seltrue(dev, flag) - dev_t dev; - int flag; +fsetown(fp, value) + struct file *fp; + int value; { - return (1); + 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)); } -selwakeup(p, coll) - register struct proc *p; - int coll; +fioctl(fp, cmd, value) + struct file *fp; + int cmd; + caddr_t value; { - 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); - } - } + return ((*fp->f_ops->fo_ioctl)(fp, cmd, value)); } -revoke() +close() { + struct a { + int fdes; + } *uap = (struct a *)u.u_ap; + register struct file *fp; + register u_char *pf; + + if ((unsigned)uap->fdes >= NOFILE || + (fp = u.u_ofile[uap->fdes]) == NULL) + RETURN (EBADF); + pf = (u_char *)&u.u_pofile[uap->fdes]; + if (*pf & UF_MAPPED) + munmapfd(uap->fdes); + u.u_ofile[uap->fdes] = NULL; + while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL) + u.u_lastfile--; + *pf = 0; + closef(fp); + /* WHAT IF u.u_error ? */ +} + +fstat() +{ + register struct file *fp; + register struct a { + int fdes; + struct stat *sb; + } *uap = (struct a *)u.u_ap; + struct stat ub; + + if ((unsigned)uap->fdes >= NOFILE || + (fp = u.u_ofile[uap->fdes]) == NULL) + RETURN (EBADF); + switch (fp->f_type) { + + case DTYPE_VNODE: + u.u_error = vn_stat((struct vnode *)fp->f_data, &ub); + break; - /* XXX */ + case DTYPE_SOCKET: + u.u_error = soo_stat((struct socket *)fp->f_data, &ub); + break; + + default: + panic("fstat"); + /*NOTREACHED*/ + } + if (u.u_error == 0) + u.u_error = copyout((caddr_t)&ub, (caddr_t)uap->sb, + sizeof (ub)); } /* * Allocate a user file descriptor. */ -ufalloc() +ufalloc(want, result) + register int want; + int *result; { - register i; - for (i=0; i u.u_lastfile) + u.u_lastfile = want; + if (result) + *result = want; + return (0); } - u.u_error = EMFILE; - return (-1); + return (EMFILE); +} + +ufavail() +{ + register int i, avail = 0; + + for (i = 0; i < NOFILE; i++) + if (u.u_ofile[i] == NULL) + avail++; + return (avail); } struct file *lastf; @@ -401,15 +317,15 @@ struct file *lastf; * Initialize the descriptor * to point at the file structure. */ -struct file * -falloc() +falloc(resultfp, resultfd) + struct file **resultfp; + int *resultfd; { register struct file *fp; - register i; + int error, i; - i = ufalloc(); - if (i < 0) - return (NULL); + if (error = ufalloc(0, &i)) + return (error); if (lastf == 0) lastf = file; for (fp = lastf; fp < fileNFILE; fp++) @@ -419,58 +335,29 @@ 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++; + fp->f_count = 1; + fp->f_data = 0; fp->f_offset = 0; - fp->f_inode = 0; + fp->f_cred = u.u_cred; + crhold(fp->f_cred); lastf = fp + 1; - return (fp); -} -/* - * 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. - */ -struct file * -getf(f) - register int f; -{ - register struct file *fp; - - if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) { - u.u_error = EBADF; - return (NULL); - } - return (fp); + if (resultfp) + *resultfp = fp; + if (resultfd) + *resultfd = i; + return (0); } /* * 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) register struct file *fp; - int nouser, flags; { - register struct inode *ip; - register struct mount *mp; - int flag, mode; - dev_t dev; - register int (*cfunc)(); if (fp == NULL) return; @@ -478,66 +365,107 @@ closef(fp, nouser, flags) fp->f_count--; return; } - if (fp->f_type == DTYPE_SOCKET) { - u.u_error = 0; /* XXX */ - soclose(fp->f_socket, nouser); - if (nouser == 0 && u.u_error) - return; - fp->f_socket = 0; - fp->f_count = 0; - return; - } - 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 < 1) + panic("closef: count < 1"); + (*fp->f_ops->fo_close)(fp); + crfree(fp->f_cred); fp->f_count = 0; +} - 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. + */ +flock() +{ + register struct a { + int fdes; + int how; + } *uap = (struct a *)u.u_ap; + register struct file *fp; - default: + if ((unsigned)uap->fdes >= NOFILE || + (fp = u.u_ofile[uap->fdes]) == NULL) + RETURN (EBADF); + if (fp->f_type != DTYPE_VNODE) { + u.u_error = EOPNOTSUPP; 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); + if (uap->how & LOCK_UN) { + vn_unlock(fp, FSHLOCK|FEXLOCK); + return; } - (*cfunc)(dev, flag, fp); + if ((uap->how & (LOCK_SH | LOCK_EX)) == 0) + return; /* error? */ + if (uap->how & LOCK_EX) + uap->how &= ~LOCK_SH; + /* avoid work... */ + if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) || + (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH)) + return; + u.u_error = vn_lock(fp, uap->how); } -opause() +/* + * File Descriptor pseudo-device driver (/dev/fd/). + * + * Fred Blonder - U of Maryland 11-Sep-1984 + * + * 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); + struct file *fp, *wfp; + int indx, dfd, rwmode; + + /* + * Note the horrid kludge here: u.u_r.r_val1 contains the value + * of the new file descriptor, which was set before the call to + * vn_open() by copen() in vfs_syscalls.c + */ + indx = u.u_r.r_val1; /* XXX */ + if ((unsigned)indx >= NOFILE || (fp = u.u_ofile[indx]) == NULL) + return (EBADF); + dfd = minor(dev); + if ((unsigned)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL) + return (EBADF); + /* + * We must explicitly test for this case because ufalloc() may + * have allocated us the same file desriptor we are referring + * to, if the proccess referred to an invalid (closed) descriptor. + * Ordinarily this would be caught by the check for NULL above, + * but by the time we reach this routine u_pofile[minor(dev)] + * could already be set to point to our file struct. + */ + if (fp == wfp) + return (EBADF); + /* + * Fake a ``dup()'' sys call. + * Check that the mode the file is being opened + * for is consistent with the mode of the existing + * descriptor. This isn't as clean as it should be, + * but this entire driver is a real kludge anyway. + */ + rwmode = mode & (FREAD|FWRITE); + if ((fp->f_flag & rwmode) != rwmode) + return (EACCES); + /* + * Delete references to this pseudo-device. + * Note that fp->f_count is guaranteed == 1, and + * that fp references the vnode for this driver. + */ + if (fp->f_count != 1 || fp->f_type != DTYPE_VNODE) + panic("fdopen"); + vrele((struct vnode *)fp->f_data); + fp->f_count = 0; + /* + * Dup the file descriptor. + */ + dupit(indx, wfp, u.u_pofile[dfd]); + return (0); }