-/* kern_descrip.c 5.2 82/07/24 */
+/* kern_descrip.c 5.25 83/06/12 */
#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/inline.h"
#include "../h/socket.h"
#include "../h/socketvar.h"
#include "../h/mount.h"
+#include "../h/stat.h"
-#include "../h/descrip.h"
+#include "../h/ioctl.h"
/*
* Descriptor management.
/*
* TODO:
- * getf should be renamed
- * ufalloc side effects are gross
+ * increase NOFILE
+ * eliminate u.u_error side effects
*/
/*
* System calls on descriptors.
*/
-dstd()
+getdtablesize()
{
u.u_r.r_val1 = NOFILE;
}
+getdopt()
+{
+
+}
+
+setdopt()
+{
+
+}
+
dup()
{
register struct a {
int i;
} *uap = (struct a *) u.u_ap;
- register struct file *fp;
- register int j;
+ struct file *fp;
+ int j;
if (uap->i &~ 077) { uap->i &= 077; dup2(); return; } /* XXX */
fp = getf(uap->i);
if (fp == 0)
return;
- j = ufalloc();
+ j = ufalloc(0);
if (j < 0)
return;
- u.u_ofile[j] = fp;
- fp->f_count++;
+ dupit(j, fp, u.u_pofile[uap->i]);
}
dup2()
if (uap->i == uap->j)
return;
if (u.u_ofile[uap->j]) {
- closef(u.u_ofile[uap->j], 0);
+ if (u.u_pofile[uap->j] & UF_MAPPED)
+ munmapfd(uap->j);
+ closef(u.u_ofile[uap->j], u.u_pofile[uap->j]);
if (u.u_error)
return;
/* u.u_ofile[uap->j] = 0; */
+ /* u.u_pofile[uap->j] = 0; */
}
- u.u_ofile[uap->j] = fp;
- fp->f_count++;
+ dupit(uap->j, fp, u.u_pofile[uap->i]);
}
-close()
-{
- register struct a {
- int i;
- } *uap = (struct a *)u.u_ap;
+dupit(fd, fp, lockflags)
+ int fd;
register struct file *fp;
+ register int lockflags;
+{
- fp = getf(uap->i);
- if (fp == 0)
- return;
- u.u_ofile[uap->i] = 0;
- closef(fp, 0);
- /* WHAT IF u.u_error ? */
+ u.u_ofile[fd] = fp;
+ u.u_pofile[fd] = lockflags;
+ fp->f_count++;
+/* THIS DOESN'T BELONG HERE */
+ if (lockflags&UF_SHLOCK)
+ ((struct inode *)fp->f_data)->i_shlockc++;
+ if (lockflags&UF_EXLOCK)
+ ((struct inode *)fp->f_data)->i_exlockc++;
+/* END DOESN'T BELONG */
}
-dtype()
+/*
+ * The file control system call.
+ */
+fcntl()
{
- register struct a {
- int d;
- struct dtype *dtypeb;
- } *uap = (struct a *)u.u_ap;
register struct file *fp;
- struct dtype adtype;
+ register struct a {
+ int fdes;
+ int cmd;
+ int arg;
+ } *uap;
+ register i;
+ register char *pop;
- 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;
+ uap = (struct a *)u.u_ap;
+ fp = getf(uap->fdes);
+ if (fp == NULL)
return;
- }
-}
+ pop = &u.u_pofile[uap->fdes];
+ switch(uap->cmd) {
+ case 0:
+ i = uap->arg;
+ if (i < 0 || i > NOFILE) {
+ u.u_error = EINVAL;
+ return;
+ }
+ if ((i = ufalloc(i)) < 0)
+ return;
+ dupit(i, fp, *pop);
+ break;
-dwrap()
-{
- register struct a {
- int d;
- struct dtype *dtypeb;
- } *uap = (struct a *)u.u_ap;
- register struct file *fp;
- struct dtype adtype;
+ case 1:
+ u.u_r.r_val1 = *pop & 1;
+ break;
- 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 */
-}
+ case 2:
+ *pop = (*pop &~ 1) | (uap->arg & 1);
+ break;
-dselect()
-{
+ case 3:
+ u.u_r.r_val1 = fp->f_flag+FOPEN;
+ break;
-}
+ case 4:
+ 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;
-dnblock()
-{
- register struct a {
- int d;
- int how;
- } *uap = (struct a *)u.u_ap;
+ case 5:
+ u.u_error = fsetown(fp, uap->arg);
+ break;
+
+ case 6:
+ u.u_error = fgetown(fp, &u.u_r.r_val1);
+ break;
- /* XXX */
+ default:
+ u.u_error = EINVAL;
+ }
}
-dsignal()
+fset(fp, bit, value)
+ struct file *fp;
+ int bit, value;
{
- register struct a {
- int d;
- int how;
- } *uap = (struct a *)u.u_ap;
- /* XXX */
+ if (value)
+ fp->f_flag |= bit;
+ else
+ fp->f_flag &= ~bit;
+ return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
+ (caddr_t)&value));
}
-int nselcoll;
-/*
- * Select system call.
- */
-oselect()
+fgetown(fp, valuep)
+ struct file *fp;
+ int *valuep;
{
- register struct uap {
- int nfd;
- fd_set *rp, *wp;
- int timo;
- } *ap = (struct uap *)u.u_ap;
- fd_set rd, wr;
- int nfds = 0, readable = 0, writeable = 0;
- time_t t = time;
- int s, tsel, ncoll, rem;
-
- if (ap->nfd > NOFILE)
- ap->nfd = NOFILE;
- if (ap->nfd < 0) {
- u.u_error = EBADF;
- return;
- }
- if (ap->rp && copyin((caddr_t)ap->rp,(caddr_t)&rd,sizeof(fd_set)))
- return;
- if (ap->wp && copyin((caddr_t)ap->wp,(caddr_t)&wr,sizeof(fd_set)))
- return;
-retry:
- ncoll = nselcoll;
- u.u_procp->p_flag |= SSEL;
- if (ap->rp)
- readable = selscan(ap->nfd, rd, &nfds, FREAD);
- if (ap->wp)
- writeable = selscan(ap->nfd, wr, &nfds, FWRITE);
- if (u.u_error)
- goto done;
- if (readable || writeable)
- goto done;
- rem = (ap->timo+999)/1000 - (time - t);
- if (ap->timo == 0 || rem <= 0)
- goto done;
- s = spl6();
- 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;
- tsel = tsleep((caddr_t)&selwait, PZERO+1, rem);
- splx(s);
- switch (tsel) {
+ int error;
- case TS_OK:
- goto retry;
+ switch (fp->f_type) {
- case TS_SIG:
- u.u_error = EINTR;
- return;
+ case DTYPE_SOCKET:
+ *valuep = ((struct socket *)fp->f_data)->so_pgrp;
+ return (0);
- case TS_TIME:
- break;
+ default:
+ error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
+ *valuep = -*valuep;
+ return (error);
}
-done:
- rd.fds_bits[0] = readable;
- wr.fds_bits[0] = writeable;
- s = sizeof (fd_set);
- if (s * NBBY > ap->nfd)
- s = (ap->nfd + NBBY - 1) / NBBY;
- u.u_r.r_val1 = nfds;
- if (ap->rp)
- (void) copyout((caddr_t)&rd, (caddr_t)ap->rp, sizeof(fd_set));
- if (ap->wp)
- (void) copyout((caddr_t)&wr, (caddr_t)ap->wp, sizeof(fd_set));
}
-selscan(nfd, fds, nfdp, flag)
- int nfd;
- fd_set fds;
- int *nfdp, flag;
-{
+fsetown(fp, value)
struct file *fp;
- struct inode *ip;
- register int bits;
- int i, able, res = 0;
-
- bits = fds.fds_bits[0];
- while (i = ffs(bits)) {
- if (i > nfd)
- break;
- bits &= ~(1<<(i-1));
- fp = u.u_ofile[i-1];
- if (fp == NULL) {
- u.u_error = EBADF;
- return (0);
- }
- 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;
- }
+ int value;
+{
- }
- if (able) {
- res |= (1<<(i-1));
- (*nfdp)++;
- }
+ if (fp->f_type == DTYPE_SOCKET) {
+ ((struct socket *)fp->f_data)->so_pgrp = value;
+ return (0);
}
- return (res);
+ if (value > 0) {
+ struct proc *p = pfind(value);
+ if (p == 0)
+ return (EINVAL);
+ value = p->p_pgrp;
+ } else
+ value = -value;
+ return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
}
-/*ARGSUSED*/
-seltrue(dev, flag)
- dev_t dev;
- int flag;
+fioctl(fp, cmd, value)
+ struct file *fp;
+ int cmd;
+ caddr_t value;
{
- return (1);
+ return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
}
-selwakeup(p, coll)
- register struct proc *p;
- int coll;
+close()
{
- int s;
+ register struct a {
+ int i;
+ } *uap = (struct a *)u.u_ap;
+ register struct file *fp;
+ register u_char *pf;
- 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);
- }
- }
+ fp = getf(uap->i);
+ if (fp == 0)
+ return;
+ pf = (u_char *)&u.u_pofile[uap->i];
+ if (*pf & UF_MAPPED)
+ munmapfd(uap->i);
+ if (*pf & (UF_SHLOCK|UF_EXLOCK))
+ unlockf(fp, pf);
+ closef(fp);
+ /* WHAT IF u.u_error ? */
+ u.u_ofile[uap->i] = NULL;
+ *pf = 0;
}
+fstat()
+{
+ register struct file *fp;
+ register struct a {
+ int fdes;
+ struct stat *sb;
+ } *uap;
+ struct stat ub;
+
+ uap = (struct a *)u.u_ap;
+ fp = getf(uap->fdes);
+ if (fp == 0)
+ return;
+ switch (fp->f_type) {
+
+ case DTYPE_INODE:
+ u.u_error = ino_stat((struct inode *)fp->f_data, &ub);
+ break;
+
+ 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(&ub, uap->sb, sizeof (ub));
+}
/*
* Allocate a user file descriptor.
*/
-ufalloc()
+ufalloc(i)
+ register int i;
{
- register i;
- for (i=0; i<NOFILE; i++)
+ for (; i < NOFILE; i++)
if (u.u_ofile[i] == NULL) {
u.u_r.r_val1 = i;
u.u_pofile[i] = 0;
return (-1);
}
+ufavail()
+{
+ register int i, avail = 0;
+
+ for (i = 0; i < NOFILE; i++)
+ if (u.u_ofile[i] == NULL)
+ avail++;
+ return (avail);
+}
+
struct file *lastf;
/*
* Allocate a user file descriptor
register struct file *fp;
register i;
- i = ufalloc();
+ i = ufalloc(0);
if (i < 0)
return (NULL);
if (lastf == 0)
return (NULL);
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;
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.
+ * Critical paths should use the GETF macro.
*/
struct file *
getf(f)
/*
* 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.
+ * Decrement reference count on file structure.
+ * If last reference not going away, but no more
+ * references except in message queues, run a
+ * garbage collect. This would better be done by
+ * forcing a gc() to happen sometime soon, rather
+ * than running one each time.
*/
-closef(fp, nouser)
+closef(fp)
register struct file *fp;
{
- register struct inode *ip;
- register struct mount *mp;
- int flag, mode;
- dev_t dev;
- register int (*cfunc)();
if (fp == NULL)
return;
if (fp->f_count > 1) {
fp->f_count--;
+ if (fp->f_count == fp->f_msgcount)
+ unp_gc();
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;
- ilock(ip);
- iput(ip);
+ (*fp->f_ops->fo_close)(fp);
fp->f_count = 0;
-
- switch (mode) {
-
- case IFCHR:
- cfunc = cdevsw[major(dev)].d_close;
-#ifdef EFS
- /*
- * Every close() must call the driver if the
- * extended file system is being used -- not
- * just the last close. Pass along the file
- * pointer for reference later.
- */
- if (major(dev) == efs_major) {
- (*cfunc)(dev, flag, fp, nouser);
- return;
- }
-#endif
- 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;
-
- 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);
- }
- (*cfunc)(dev, flag, fp);
}
-#ifdef CAD
/*
- * chfile -- change all references to the inode named by
- * device/inum to the file referred to by fd.
- * Used by init to remove all references to the device.
+ * Apply an advisory lock on a file descriptor.
*/
-chfile()
+flock()
{
- register struct file *fp;
- register struct inode *from;
- register struct inode *to;
- off_t offset;
- dev_t dev;
- int rw;
- struct a {
- int device; /* actually dev_t */
- int inum; /* actually ino_t */
+ register struct a {
int fd;
- } *uap;
+ int how;
+ } *uap = (struct a *)u.u_ap;
+ register struct file *fp;
+ register u_char *pf;
+ int cmd;
- if (!suser()) {
- u.u_error = EPERM;
- return;
- }
- uap = (struct a *) u.u_ap;
fp = getf(uap->fd);
- if (fp == NULL) {
- u.u_error = EBADF;
- return;
- }
- if (fp->f_type == DTYPE_SOCKET) {
- u.u_error = EINVAL;
+ if (fp == NULL)
return;
- }
- for (from = &inode[0]; from < &inode[ninode]; from++)
- if (from->i_number == (ino_t)uap->inum
- && from->i_dev == (dev_t)uap->device)
- break;
- if (from >= &inode[ninode]) {
- u.u_error = ENXIO;
+ cmd = uap->how;
+ pf = (u_char *)&u.u_pofile[uap->fd];
+ if (cmd & LOCK_UN) {
+ unlockf(fp, pf);
return;
}
- offset = fp->f_offset;
- to = fp->f_inode;
- from->i_count++;
- for (fp = &file[0]; fp < &file[nfile]; fp++) {
- if (fp->f_count > 0 && fp->f_inode == from) {
- fp->f_inode = to;
- to->i_count++;
- fp->f_offset = offset;
- rw |= fp->f_flag & FWRITE;
- iput(from);
- }
- }
/*
- * This inode is no longer referenced.
- * Switch out to the appropriate close
- * routine, if required
+ * No reason to write lock a file we've already
+ * write locked, similarly with a read lock.
*/
- dev = (dev_t)from->i_un.i_rdev;
- switch(from->i_mode & IFMT) {
+ if ((*pf & UF_EXLOCK) && (cmd & LOCK_EX) ||
+ (*pf & UF_SHLOCK) && (cmd & LOCK_SH))
+ return;
+ switch (fp->f_type) {
- case IFCHR:
- (*cdevsw[major(dev)].d_close)(dev, rw);
+ case DTYPE_INODE:
+ u.u_error = ino_lock((struct inode *)fp->f_data, pf, cmd);
break;
-
- case IFBLK:
- (*bdevsw[major(dev)].d_close)(dev, rw);
+
+ case DTYPE_SOCKET:
+ u.u_error = soo_lock((struct socket *)fp->f_data, pf, cmd);
break;
default:
+ panic("lockf");
+ }
+}
+
+unlockf(fp, pf)
+ register struct file *fp;
+ register u_char *pf;
+{
+
+ if ((*pf & (UF_SHLOCK|UF_EXLOCK)) == 0)
+ return;
+ switch (fp->f_type) {
+
+ case DTYPE_INODE:
+ ino_unlock((struct inode *)fp->f_data, *pf);
+ break;
+
+ case DTYPE_SOCKET:
+ soo_unlock((struct socket *)fp->f_data, *pf);
break;
+
+ default:
+ panic("unlockf");
}
- iput(from);
+ *pf &= ~(UF_SHLOCK|UF_EXLOCK);
}
-#endif