X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/b9429893ac917380dd8cf8b9af055982c6e675c7..88a7a62ac37860454424240400aa10e0319144c7:/usr/src/sys/kern/sys_generic.c diff --git a/usr/src/sys/kern/sys_generic.c b/usr/src/sys/kern/sys_generic.c index 2236243fcf..56ff7b8836 100644 --- a/usr/src/sys/kern/sys_generic.c +++ b/usr/src/sys/kern/sys_generic.c @@ -1,28 +1,15 @@ -/* sys_generic.c 5.11 82/08/22 */ +/* sys_generic.c 5.36 83/05/27 */ #include "../h/param.h" #include "../h/systm.h" #include "../h/dir.h" #include "../h/user.h" -#include "../h/tty.h" +#include "../h/ioctl.h" #include "../h/file.h" -#include "../h/inode.h" -#include "../h/buf.h" #include "../h/proc.h" -#include "../h/inline.h" -#include "../h/conf.h" -#include "../h/socket.h" -#include "../h/socketvar.h" -#include "../h/fs.h" -#ifdef MUSH -#include "../h/quota.h" -#include "../h/share.h" -#else -#define CHARGE(nothing) -#endif -#include "../h/vlimit.h" -#include "../h/descrip.h" #include "../h/uio.h" +#include "../h/kernel.h" +#include "../h/stat.h" /* * Read system call. @@ -60,11 +47,10 @@ readv() } auio.uio_iov = aiov; auio.uio_iovcnt = uap->iovcnt; - if (copyin((caddr_t)uap->iovp, (caddr_t)aiov, - (unsigned)(uap->iovcnt * sizeof (struct iovec)))) { - u.u_error = EFAULT; + u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov, + (unsigned)(uap->iovcnt * sizeof (struct iovec))); + if (u.u_error) return; - } rwuio(&auio, UIO_READ); } @@ -104,11 +90,10 @@ writev() } auio.uio_iov = aiov; auio.uio_iovcnt = uap->iovcnt; - if (copyin((caddr_t)uap->iovp, (caddr_t)aiov, - (unsigned)(uap->iovcnt * sizeof (struct iovec)))) { - u.u_error = EFAULT; + u.u_error = copyin((caddr_t)uap->iovp, (caddr_t)aiov, + (unsigned)(uap->iovcnt * sizeof (struct iovec))); + if (u.u_error) return; - } rwuio(&auio, UIO_WRITE); } @@ -121,7 +106,6 @@ rwuio(uio, rw) }; register struct file *fp; register struct iovec *iov; - register struct inode *ip; int i, count; GETF(fp, ((struct a *)u.u_ap)->fdes); @@ -144,312 +128,18 @@ rwuio(uio, rw) } } count = uio->uio_resid; - if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { + uio->uio_offset = fp->f_offset; + if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { if (uio->uio_resid == count) u.u_eosys = RESTARTSYS; - } else if (fp->f_type == DTYPE_SOCKET) { - int sosend(), soreceive(); - u.u_error = - (*(rw==UIO_READ?soreceive:sosend)) - (fp->f_socket, (struct sockaddr *)0, uio); - } else { - ip = fp->f_inode; - uio->uio_offset = fp->f_offset; - if ((ip->i_mode&IFMT) == IFREG) { - ilock(ip); - u.u_error = rwip(ip, uio, rw); - iunlock(ip); - } else - u.u_error = rwip(ip, uio, rw); - fp->f_offset += count - uio->uio_resid; - } - u.u_r.r_val1 = count - uio->uio_resid; -} - -rdwri(rw, ip, base, len, offset, segflg, aresid) - struct inode *ip; - caddr_t base; - int len, offset, segflg; - int *aresid; - enum uio_rw rw; -{ - struct uio auio; - struct iovec aiov; - int error; - - auio.uio_iov = &aiov; - auio.uio_iovcnt = 1; - aiov.iov_base = base; - aiov.iov_len = len; - auio.uio_resid = len; - auio.uio_offset = offset; - auio.uio_segflg = segflg; - error = rwip(ip, &auio, rw); - if (aresid) - *aresid = auio.uio_resid; - else - if (auio.uio_resid) - error = EIO; - return (error); -} - -rwip(ip, uio, rw) - register struct inode *ip; - register struct uio *uio; - enum uio_rw rw; -{ - dev_t dev = (dev_t)ip->i_rdev; - struct buf *bp; - struct fs *fs; - daddr_t lbn, bn; - register int on, type; - register unsigned n; - int size; - long bsize; - extern int mem_no; - int error = 0; - - if (rw != UIO_READ && rw != UIO_WRITE) - panic("rwip"); - if (uio->uio_offset < 0 && - ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) - return (EINVAL); if (rw == UIO_READ) - ip->i_flag |= IACC; - type = ip->i_mode&IFMT; - if (type == IFCHR) { -#ifdef QUOTA - register c = uio->uio_resid; -#endif - if (rw == UIO_READ) - (*cdevsw[major(dev)].d_read)(dev, uio); - else { - ip->i_flag |= IUPD|ICHG; - (*cdevsw[major(dev)].d_write)(dev, uio); - } - CHARGE(sc_tio * (c - uio->uio_resid)); - return (u.u_error); - } - if (rw == UIO_WRITE && type == IFREG && - uio->uio_offset + uio->uio_resid > u.u_limit[LIM_FSIZE]) { - psignal(u.u_procp, SIGXFSZ); - return (EMFILE); - } - if (type != IFBLK) { - dev = ip->i_dev; - fs = ip->i_fs; - bsize = fs->fs_bsize; } else - bsize = BLKDEV_IOSIZE; - do { - lbn = uio->uio_offset / bsize; - on = uio->uio_offset % bsize; - n = MIN((unsigned)(bsize - on), uio->uio_resid); - if (type != IFBLK) { - if (rw == UIO_READ) { - int diff = ip->i_size - uio->uio_offset; - if (diff <= 0) - return (0); - if (diff < n) - n = diff; - } - bn = fsbtodb(fs, - bmap(ip, lbn, rw == UIO_WRITE ? B_WRITE: B_READ, (int)(on+n))); - if (u.u_error || rw == UIO_WRITE && (long)bn<0) - return (u.u_error); - if (rw == UIO_WRITE && uio->uio_offset + n > ip->i_size && - (type == IFDIR || type == IFREG || type == IFLNK)) - ip->i_size = uio->uio_offset + n; - size = blksize(fs, ip, lbn); - } else { - bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE); - rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE); - rasize = size = bsize; - } - if (rw == UIO_READ) { - if ((long)bn<0) { - bp = geteblk(size); - clrbuf(bp); - } else if (ip->i_lastr + 1 == lbn) - bp = breada(dev, bn, size, rablock, rasize); - else - bp = bread(dev, bn, size); - ip->i_lastr = lbn; - } else { - int i, count; - - count = howmany(size, DEV_BSIZE); - for (i = 0; i < count; i += CLSIZE) - if (mfind(dev, bn + i)) - munhash(dev, bn + i); - if (n == bsize) - bp = getblk(dev, bn, size); - else - bp = bread(dev, bn, size); - } - n = MIN(n, size - bp->b_resid); - if (bp->b_flags & B_ERROR) { - error = EIO; - brelse(bp); - goto bad; - } - u.u_error = - uiomove(bp->b_un.b_addr+on, (u_int)n, rw, uio); - if (rw == UIO_READ) { - if (n + on == bsize || uio->uio_offset == ip->i_size) - bp->b_flags |= B_AGE; - brelse(bp); - } else { - if ((ip->i_mode&IFMT) == IFDIR) - bwrite(bp); - else if (n + on == bsize) { - bp->b_flags |= B_AGE; - bawrite(bp); - } else - bdwrite(bp); - ip->i_flag |= IUPD|ICHG; - if (u.u_ruid != 0) - ip->i_mode &= ~(ISUID|ISGID); - } - } while (u.u_error == 0 && uio->uio_resid > 0 && n != 0); -bad: - return (error); -} - -uiomove(cp, n, rw, uio) - register caddr_t cp; - register int n; - enum uio_rw rw; - register struct uio *uio; -{ - register struct iovec *iov; - int error; - u_int cnt; - - while (n > 0 && uio->uio_resid) { - iov = uio->uio_iov; - cnt = iov->iov_len; - if (cnt == 0) { - uio->uio_iov++; - uio->uio_iovcnt--; - continue; - } - if (cnt > n) - cnt = n; - switch (uio->uio_segflg) { - - case 0: - case 2: - if (rw == UIO_READ) - error = copyout(cp, iov->iov_base, cnt); - else - error = copyin(iov->iov_base, cp, cnt); - if (error) - return (error); - break; - - case 1: - if (rw == UIO_READ) - bcopy((caddr_t)cp, iov->iov_base, cnt); - else - bcopy(iov->iov_base, (caddr_t)cp, cnt); - break; - } - iov->iov_base += cnt; - iov->iov_len -= cnt; - uio->uio_resid -= cnt; - uio->uio_offset += cnt; - cp += cnt; - n -= cnt; - } - return (error); -} - -/* - * Give next character to user as result of read. - */ -ureadc(c, uio) - register int c; - register struct uio *uio; -{ - register struct iovec *iov; - -again: - if (uio->uio_iovcnt == 0) - panic("ureadc"); - iov = uio->uio_iov; - if (iov->iov_len <= 0 || uio->uio_resid <= 0) { - uio->uio_iovcnt--; - uio->uio_iov++; - goto again; - } - switch (uio->uio_segflg) { - - case 0: - if (subyte(iov->iov_base, c) < 0) - return (EFAULT); - break; - - case 1: - *iov->iov_base = c; - break; - - case 2: - if (suibyte(iov->iov_base, c) < 0) - return (EFAULT); - break; - } - iov->iov_base++; - iov->iov_len--; - uio->uio_resid--; - uio->uio_offset++; - return (0); -} - -/* - * Get next character written in by user from uio. - */ -uwritec(uio) - struct uio *uio; -{ - register struct iovec *iov; - register int c; - -again: - if (uio->uio_iovcnt <= 0 || uio->uio_resid <= 0) - panic("uwritec"); - iov = uio->uio_iov; - if (iov->iov_len == 0) { - uio->uio_iovcnt--; - uio->uio_iov++; - goto again; - } - switch (uio->uio_segflg) { - - case 0: - c = fubyte(iov->iov_base); - break; - - case 1: - c = *iov->iov_base & 0377; - break; - - case 2: - c = fuibyte(iov->iov_base); - break; - } - if (c < 0) - return (-1); - iov->iov_base++; - iov->iov_len--; - uio->uio_resid--; - uio->uio_offset++; - return (c & 0377); + u.u_error = (*fp->f_ops->fo_rw)(fp, rw, uio); + u.u_r.r_val1 = count - uio->uio_resid; + fp->f_offset += u.u_r.r_val1; } /* * Ioctl system call - * Check legality, execute common code, - * and switch out to individual device routine. */ ioctl() { @@ -472,7 +162,7 @@ ioctl() } com = uap->cmd; -#ifndef NOCOMPAT +#if defined(vax) && !defined(NOCOMPAT) /* * Map old style ioctl's into new for the * sake of backwards compatibility (sigh). @@ -486,11 +176,11 @@ ioctl() } #endif if (com == FIOCLEX) { - u.u_pofile[uap->fdes] |= EXCLOSE; + u.u_pofile[uap->fdes] |= UF_EXCLOSE; return; } if (com == FIONCLEX) { - u.u_pofile[uap->fdes] &= ~EXCLOSE; + u.u_pofile[uap->fdes] &= ~UF_EXCLOSE; return; } @@ -504,68 +194,241 @@ ioctl() u.u_error = EFAULT; return; } - if (com&IOC_IN && size) { - if (copyin(uap->cmarg, (caddr_t)data, (u_int)size)) { - u.u_error = EFAULT; - return; - } - } else - *(caddr_t *)data = uap->cmarg; - /* - * Zero the buffer on the stack so the user - * always gets back something deterministic. - */ - if ((com&IOC_OUT) && size) + if (com&IOC_IN) { + if (size) { + u.u_error = + copyin(uap->cmarg, (caddr_t)data, (u_int)size); + if (u.u_error) + return; + } else + *(caddr_t *)data = uap->cmarg; + } else if ((com&IOC_OUT) && size) + /* + * Zero the buffer on the stack so the user + * always gets back something deterministic. + */ bzero((caddr_t)data, size); + else if (com&IOC_VOID) + *(caddr_t *)data = uap->cmarg; - if (fp->f_type == DTYPE_SOCKET) - soioctl(fp->f_socket, com, data); - else { - register struct inode *ip = fp->f_inode; - int fmt = ip->i_mode & IFMT; - dev_t dev; - - if (fmt != IFCHR) { - if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) { - *(off_t *)data = ip->i_size - fp->f_offset; - goto returndata; - } - if (com != FIONBIO && com != FIOASYNC) - u.u_error = ENOTTY; - return; - } - dev = ip->i_rdev; - u.u_r.r_val1 = 0; - if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) { - u.u_eosys = RESTARTSYS; - return; - } - (*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0); - } + switch (com) { + + case FIONBIO: + u.u_error = fset(fp, FNDELAY, *(int *)data); + return; + + case FIOASYNC: + u.u_error = fset(fp, FASYNC, *(int *)data); + return; -returndata: + case FIOSETOWN: + u.u_error = fsetown(fp, *(int *)data); + return; + + case FIOGETOWN: + u.u_error = fgetown(fp, (int *)data); + return; + } + u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data); /* * Copy any data to user, size was * already set and checked above. */ - if (u.u_error == 0 && (com&IOC_OUT)) - if (size && copyout(data, uap->cmarg, (u_int)size)) - u.u_error = EFAULT; + if (u.u_error == 0 && (com&IOC_OUT) && size) + u.u_error = copyout(data, uap->cmarg, (u_int)size); } +int unselect(); +int nselcoll; /* - * Do nothing specific version of line - * discipline specific ioctl command. + * Select system call. */ +select() +{ + register struct uap { + int nd; + long *in, *ou, *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) + uap->nd = NOFILE; /* forgiving, if slightly wrong */ + +#define getbits(name, x) \ + if (uap->name) { \ + u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \ + sizeof (ibits[x])); \ + if (u.u_error) \ + goto done; \ + } else \ + ibits[x] = 0; + getbits(in, 0); + getbits(ou, 1); + getbits(ex, 2); +#undef getbits + + if (uap->tv) { + u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv, + sizeof (atv)); + if (u.u_error) + 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) { \ + int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \ + sizeof (obits[x])); \ + if (error) \ + u.u_error = error; \ + } + putbits(in, 0); + putbits(ou, 1); + putbits(ex, 2); +#undef putbits +} + +unselect(p) + register struct proc *p; +{ + register int s = spl6(); + + switch (p->p_stat) { + + case SSLEEP: + setrun(p); + break; + + case SSTOP: + unsleep(p); + break; + } + splx(s); +} + +selscan(ibits, obits) + int *ibits, *obits; +{ + register int which, bits, i; + int flag; + struct file *fp; + 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_ops->fo_select)(fp, flag)) { + obits[which] |= (1<<(i-1)); + n++; + } + } + } + return (n); +} + /*ARGSUSED*/ -nullioctl(tp, cmd, data, flags) - struct tty *tp; - char *data; - int flags; +seltrue(dev, flag) + dev_t dev; + int flag; { -#ifdef lint - tp = tp; data = data; flags = flags; -#endif - return (cmd); + return (1); +} + +selwakeup(p, coll) + register struct proc *p; + int coll; +{ + + if (coll) { + nselcoll++; + wakeup((caddr_t)&selwait); + } + if (p) { + int s = spl6(); + if (p->p_wchan == (caddr_t)&selwait) + setrun(p); + else if (p->p_flag & SSEL) + p->p_flag &= ~SSEL; + splx(s); + } +} + +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; + u.u_error = (*fp->f_ops->fo_stat)(fp, &ub); + if (u.u_error == 0) + u.u_error = copyout(&ub, uap->sb, sizeof (ub)); }