+ if (((unsigned)uap->fdes) >= NOFILE ||
+ (fp = u.u_ofile[uap->fdes]) == NULL ||
+ (fp->f_flag & FREAD) == 0)
+ RETURN (EBADF);
+ aiov.iov_base = (caddr_t)uap->cbuf;
+ aiov.iov_len = uap->count;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_resid = uap->count;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_USERSPACE;
+#ifdef KTRACE
+ /*
+ * if tracing, save a copy of iovec
+ */
+ if (KTRPOINT(p, KTR_GENIO))
+ ktriov = aiov;
+#endif
+ cnt = uap->count;
+ if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
+ if (auio.uio_resid != cnt && (error == ERESTART ||
+ error == EINTR || error == EWOULDBLOCK))
+ error = 0;
+ cnt -= auio.uio_resid;
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_GENIO) && error == 0)
+ ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
+#endif
+ *retval = cnt;
+ RETURN (error);
+}
+
+/*
+ * Scatter read system call.
+ */
+readv(p, uap, retval)
+ struct proc *p;
+ register struct args {
+ int fdes;
+ struct iovec *iovp;
+ unsigned iovcnt;
+ } *uap;
+ int *retval;
+{
+ register struct file *fp;
+ struct uio auio;
+ register struct iovec *iov;
+ struct iovec aiov[UIO_SMALLIOV];
+ long i, cnt, error = 0;
+#ifdef KTRACE
+ struct iovec *ktriov = NULL;
+#endif
+
+ if (((unsigned)uap->fdes) >= NOFILE ||
+ (fp = u.u_ofile[uap->fdes]) == NULL ||
+ (fp->f_flag & FREAD) == 0)
+ RETURN (EBADF);
+ if (uap->iovcnt > UIO_SMALLIOV) {
+ if (uap->iovcnt > UIO_MAXIOV)
+ RETURN (EINVAL);
+ MALLOC(iov, struct iovec *,
+ sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
+ } else
+ iov = aiov;
+ auio.uio_iov = iov;
+ auio.uio_iovcnt = uap->iovcnt;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_USERSPACE;
+ if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
+ uap->iovcnt * sizeof (struct iovec)))
+ goto done;
+ auio.uio_resid = 0;
+ for (i = 0; i < uap->iovcnt; i++) {
+ if (iov->iov_len < 0) {
+ error = EINVAL;
+ goto done;
+ }
+ auio.uio_resid += iov->iov_len;
+ if (auio.uio_resid < 0) {
+ error = EINVAL;
+ goto done;
+ }
+ iov++;