/* 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/ioctl.h" #include "../h/file.h" #include "../h/proc.h" #include "../h/uio.h" #include "../h/kernel.h" #include "../h/stat.h" /* * Read system call. */ read() { register struct a { int fdes; char *cbuf; unsigned count; } *uap = (struct a *)u.u_ap; struct uio auio; struct iovec aiov; aiov.iov_base = (caddr_t)uap->cbuf; aiov.iov_len = uap->count; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; rwuio(&auio, UIO_READ); } readv() { register struct a { int fdes; struct iovec *iovp; int iovcnt; } *uap = (struct a *)u.u_ap; struct uio auio; struct iovec aiov[16]; /* XXX */ if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { u.u_error = EINVAL; return; } auio.uio_iov = aiov; auio.uio_iovcnt = uap->iovcnt; 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); } /* * Write system call */ write() { register struct a { int fdes; char *cbuf; int count; } *uap = (struct a *)u.u_ap; struct uio auio; struct iovec aiov; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; aiov.iov_base = uap->cbuf; aiov.iov_len = uap->count; rwuio(&auio, UIO_WRITE); } writev() { register struct a { int fdes; struct iovec *iovp; int iovcnt; } *uap = (struct a *)u.u_ap; struct uio auio; struct iovec aiov[16]; /* XXX */ if (uap->iovcnt <= 0 || uap->iovcnt > sizeof(aiov)/sizeof(aiov[0])) { u.u_error = EINVAL; return; } auio.uio_iov = aiov; auio.uio_iovcnt = uap->iovcnt; 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); } rwuio(uio, rw) register struct uio *uio; enum uio_rw rw; { struct a { int fdes; }; register struct file *fp; register struct iovec *iov; int i, count; GETF(fp, ((struct a *)u.u_ap)->fdes); if ((fp->f_flag&(rw==UIO_READ ? FREAD : FWRITE)) == 0) { u.u_error = EBADF; return; } uio->uio_resid = 0; uio->uio_segflg = 0; iov = uio->uio_iov; for (i = 0; i < uio->uio_iovcnt; i++) { if (iov->iov_len < 0) { u.u_error = EINVAL; return; } uio->uio_resid += iov->iov_len; if (uio->uio_resid < 0) { u.u_error = EINVAL; return; } } count = uio->uio_resid; 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 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 */ ioctl() { register struct file *fp; struct a { int fdes; int cmd; caddr_t cmarg; } *uap; register int com; register u_int size; char data[IOCPARM_MASK+1]; uap = (struct a *)u.u_ap; if ((fp = getf(uap->fdes)) == NULL) return; if ((fp->f_flag & (FREAD|FWRITE)) == 0) { u.u_error = EBADF; return; } com = uap->cmd; #if defined(vax) && !defined(NOCOMPAT) /* * Map old style ioctl's into new for the * sake of backwards compatibility (sigh). */ if ((com&~0xffff) == 0) { com = mapioctl(com); if (com == 0) { u.u_error = EINVAL; return; } } #endif if (com == FIOCLEX) { u.u_pofile[uap->fdes] |= UF_EXCLOSE; return; } if (com == FIONCLEX) { u.u_pofile[uap->fdes] &= ~UF_EXCLOSE; return; } /* * Interpret high order word to find * amount of data to be copied to/from the * user's address space. */ size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16; if (size > sizeof (data)) { u.u_error = EFAULT; return; } 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; switch (com) { case FIONBIO: u.u_error = fset(fp, FNDELAY, *(int *)data); return; case FIOASYNC: u.u_error = fset(fp, FASYNC, *(int *)data); return; 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) && size) u.u_error = copyout(data, uap->cmarg, (u_int)size); } int unselect(); int nselcoll; /* * 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*/ seltrue(dev, flag) dev_t dev; int flag; { 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)); }