xref: /csrg-svn/sys/kern/sys_generic.c (revision 7746)
1*7746Sroot /*	sys_generic.c	5.9	82/08/14	*/
27423Sroot 
37423Sroot #include "../h/param.h"
47423Sroot #include "../h/systm.h"
57423Sroot #include "../h/dir.h"
67423Sroot #include "../h/user.h"
77423Sroot #include "../h/tty.h"
87423Sroot #include "../h/file.h"
97423Sroot #include "../h/inode.h"
107423Sroot #include "../h/buf.h"
117423Sroot #include "../h/proc.h"
127423Sroot #include "../h/inline.h"
137423Sroot #include "../h/conf.h"
147423Sroot #include "../h/socket.h"
157423Sroot #include "../h/socketvar.h"
167423Sroot #include "../h/cmap.h"
177423Sroot #include "../h/vlimit.h"
187423Sroot #include "../h/fs.h"
197487Skre #ifdef MUSH
207487Skre #include "../h/quota.h"
217487Skre #include "../h/share.h"
227487Skre #else
237487Skre #define	CHARGE(nothing)
247487Skre #endif
257500Sroot #include "../h/descrip.h"
267714Sroot #include "../h/uio.h"
277423Sroot 
287423Sroot /*
297423Sroot  * Read system call.
307423Sroot  */
317423Sroot read()
327423Sroot {
337423Sroot 	register struct file *fp;
347423Sroot 	register struct inode *ip;
357423Sroot 	register struct a {
367423Sroot 		int	fdes;
377423Sroot 		char	*cbuf;
387423Sroot 		unsigned count;
397423Sroot 	} *uap;
40*7746Sroot 	struct uio auio;
41*7746Sroot 	struct iovec aiov;
427423Sroot 
437423Sroot 	uap = (struct a *)u.u_ap;
447423Sroot 	if ((int)uap->count < 0) {
457423Sroot 		u.u_error = EINVAL;
467423Sroot 		return;
477423Sroot 	}
487423Sroot 	GETF(fp, uap->fdes);
497423Sroot 	if ((fp->f_flag&FREAD) == 0) {
507423Sroot 		u.u_error = EBADF;
517423Sroot 		return;
527423Sroot 	}
53*7746Sroot 	aiov.iov_base = (caddr_t)uap->cbuf;
54*7746Sroot 	aiov.iov_len = uap->count;
55*7746Sroot 	auio.uio_iov = &aiov;
56*7746Sroot 	auio.uio_iovcnt = 1;
57*7746Sroot 	auio.uio_segflg = 0;
58*7746Sroot 	auio.uio_resid = uap->count;
59*7746Sroot 	u.u_base = (caddr_t)0xc0000000;
60*7746Sroot 	u.u_count = 0x40000000;
617423Sroot 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
62*7746Sroot 		if (auio.uio_resid == uap->count)
637423Sroot 			u.u_eosys = RESTARTSYS;
647500Sroot 	} else if (fp->f_type == DTYPE_SOCKET)
65*7746Sroot 		u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0, &auio);
667423Sroot 	else {
677423Sroot 		ip = fp->f_inode;
68*7746Sroot 		auio.uio_offset = fp->f_offset;
697423Sroot 		if ((ip->i_mode&IFMT) == IFREG) {
707423Sroot 			ilock(ip);
71*7746Sroot 			u.u_error = readip(ip, &auio);
727423Sroot 			iunlock(ip);
737423Sroot 		} else
74*7746Sroot 			u.u_error = readip(ip, &auio);
75*7746Sroot 		fp->f_offset += uap->count - auio.uio_resid;
767423Sroot 	}
77*7746Sroot 	u.u_r.r_val1 = uap->count - auio.uio_resid;
787423Sroot }
797423Sroot 
807423Sroot /*
817423Sroot  * Write system call
827423Sroot  */
837423Sroot write()
847423Sroot {
857423Sroot 	register struct file *fp;
867423Sroot 	register struct inode *ip;
877423Sroot 	register struct a {
887423Sroot 		int	fdes;
897423Sroot 		char	*cbuf;
907423Sroot 		unsigned count;
917423Sroot 	} *uap;
927423Sroot 
937423Sroot 	uap = (struct a *)u.u_ap;
947423Sroot 	if ((int)uap->count < 0) {
957423Sroot 		u.u_error = EINVAL;
967423Sroot 		return;
977423Sroot 	}
987423Sroot 	GETF(fp, uap->fdes);
997423Sroot 	if ((fp->f_flag&FWRITE) == 0) {
1007423Sroot 		u.u_error = EBADF;
1017423Sroot 		return;
1027423Sroot 	}
1037423Sroot 	u.u_base = (caddr_t)uap->cbuf;
1047423Sroot 	u.u_count = uap->count;
1057423Sroot 	u.u_segflg = 0;
1067423Sroot 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
1077423Sroot 		if (u.u_count == uap->count)
1087423Sroot 			u.u_eosys = RESTARTSYS;
1097500Sroot 	} else if (fp->f_type == DTYPE_SOCKET)
1107423Sroot 		u.u_error = sosend(fp->f_socket, (struct sockaddr *)0);
1117423Sroot 	else {
1127423Sroot 		ip = fp->f_inode;
1137699Ssam 		if (fp->f_flag&FAPPEND)
1147500Sroot 			fp->f_offset = ip->i_size;
1157423Sroot 		u.u_offset = fp->f_offset;
1167423Sroot 		if ((ip->i_mode&IFMT) == IFREG) {
1177423Sroot 			ilock(ip);
1187423Sroot 			writei(ip);
1197423Sroot 			iunlock(ip);
1207423Sroot 		} else
1217423Sroot 			writei(ip);
1227423Sroot 		fp->f_offset += uap->count - u.u_count;
1237423Sroot 	}
1247423Sroot 	u.u_r.r_val1 = uap->count - u.u_count;
1257423Sroot }
1267423Sroot 
1277500Sroot readv()
1287500Sroot {
1297423Sroot 
1307500Sroot }
1317500Sroot 
1327500Sroot writev()
1337500Sroot {
1347500Sroot 
1357500Sroot }
1367500Sroot 
1377423Sroot /*
1387423Sroot  * Ioctl system call
1397624Ssam  * Check legality, execute common code,
1407624Ssam  * and switch out to individual device routine.
1417423Sroot  */
1427423Sroot ioctl()
1437423Sroot {
1447423Sroot 	register struct file *fp;
1457624Ssam 	struct a {
1467423Sroot 		int	fdes;
1477423Sroot 		int	cmd;
1487423Sroot 		caddr_t	cmarg;
1497423Sroot 	} *uap;
1507624Ssam 	register int com, size;
1517624Ssam 	char data[IOCPARM_MASK+1];
1527423Sroot 
1537423Sroot 	uap = (struct a *)u.u_ap;
1547423Sroot 	if ((fp = getf(uap->fdes)) == NULL)
1557423Sroot 		return;
1567423Sroot 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
1577423Sroot 		u.u_error = EBADF;
1587423Sroot 		return;
1597423Sroot 	}
1607624Ssam 	com = uap->cmd;
1617624Ssam 
1627699Ssam #ifndef NOCOMPAT
1637624Ssam 	/*
1647624Ssam 	 * Map old style ioctl's into new for the
1657624Ssam 	 * sake of backwards compatibility (sigh).
1667624Ssam 	 */
1677624Ssam 	if ((com&~0xffff) == 0) {
1687624Ssam 		com = mapioctl(com);
1697624Ssam 		if (com == 0) {
1707624Ssam 			u.u_error = EINVAL;
1717624Ssam 			return;
1727624Ssam 		}
1737624Ssam 	}
1747624Ssam #endif
1757624Ssam 	if (com == FIOCLEX) {
1767423Sroot 		u.u_pofile[uap->fdes] |= EXCLOSE;
1777423Sroot 		return;
1787423Sroot 	}
1797624Ssam 	if (com == FIONCLEX) {
1807423Sroot 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
1817423Sroot 		return;
1827423Sroot 	}
1837624Ssam 
1847624Ssam 	/*
1857624Ssam 	 * Interpret high order word to find
1867624Ssam 	 * amount of data to be copied to/from the
1877624Ssam 	 * user's address space.
1887624Ssam 	 * (this'll have to change if we have in+out ioctls)
1897624Ssam 	 */
1907624Ssam 	size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
1917624Ssam 	if (size > sizeof (data)) {
1927624Ssam 		u.u_error = EFAULT;
1937423Sroot 		return;
1947423Sroot 	}
1957699Ssam 	if (com&IOC_IN && size) {
1967624Ssam 		if (copyin(uap->cmarg, (caddr_t)data, size)) {
1977624Ssam 			u.u_error = EFAULT;
1987624Ssam 			return;
1997624Ssam 		}
2007624Ssam 	} else
2017624Ssam 		*(caddr_t *)data = uap->cmarg;
2027624Ssam 	/*
2037624Ssam 	 * Zero the buffer on the stack so the user
2047624Ssam 	 * always gets back something deterministic.
2057624Ssam 	 */
2067624Ssam 	if ((com&IOC_OUT) && size)
2077624Ssam 		bzero((caddr_t)data, size);
2087423Sroot 
2097624Ssam 	if (fp->f_type == DTYPE_SOCKET)
2107624Ssam 		soioctl(fp->f_socket, com, data);
2117624Ssam 	else {
2127624Ssam 		register struct inode *ip = fp->f_inode;
2137624Ssam 		int fmt = ip->i_mode & IFMT;
2147624Ssam 		dev_t dev;
2157624Ssam 
2167624Ssam 		if (fmt != IFCHR) {
2177624Ssam 			if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
2187624Ssam 				*(off_t *)data = ip->i_size - fp->f_offset;
2197624Ssam 				goto returndata;
2207624Ssam 			}
2217624Ssam 			if (com != FIONBIO && com != FIOASYNC)
2227624Ssam 				u.u_error = ENOTTY;
2237423Sroot 			return;
2247624Ssam 		}
2257624Ssam 		dev = ip->i_rdev;
2267624Ssam 		u.u_r.r_val1 = 0;
2277624Ssam 		if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
2287624Ssam 			u.u_eosys = RESTARTSYS;
2297624Ssam 			return;
2307624Ssam 		}
2317624Ssam 		(*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0);
2327423Sroot 	}
2337624Ssam 
2347624Ssam returndata:
2357624Ssam 	/*
2367624Ssam 	 * Copy any data to user, size was
2377624Ssam 	 * already set and checked above.
2387624Ssam 	 */
2397699Ssam 	if (u.u_error == 0 && com&IOC_OUT)
2407699Ssam 		if (size && copyout(data, uap->cmarg, size))
2417699Ssam 			u.u_error = EFAULT;
2427423Sroot }
2437423Sroot 
2447423Sroot /*
2457423Sroot  * Do nothing specific version of line
2467423Sroot  * discipline specific ioctl command.
2477423Sroot  */
2487423Sroot /*ARGSUSED*/
2497624Ssam nullioctl(tp, cmd, data, flags)
2507423Sroot 	struct tty *tp;
2517624Ssam 	char *data;
2527624Ssam 	int flags;
2537423Sroot {
2547423Sroot 
2557624Ssam #ifdef lint
2567624Ssam 	tp = tp; data = data; flags = flags;
2577624Ssam #endif
2587423Sroot 	return (cmd);
2597423Sroot }
2607423Sroot 
2617423Sroot /*
2627423Sroot  * Read the file corresponding to
2637423Sroot  * the inode pointed at by the argument.
2647423Sroot  * The actual read arguments are found
2657423Sroot  * in the variables:
2667423Sroot  *	u_base		core address for destination
2677423Sroot  *	u_offset	byte offset in file
2687423Sroot  *	u_count		number of bytes to read
2697423Sroot  *	u_segflg	read to kernel/user/user I
2707423Sroot  */
2717423Sroot readi(ip)
2727423Sroot 	register struct inode *ip;
2737423Sroot {
2747423Sroot 	struct buf *bp;
2757423Sroot 	struct fs *fs;
2767423Sroot 	dev_t dev;
2777423Sroot 	daddr_t lbn, bn;
2787423Sroot 	off_t diff;
2797423Sroot 	register int on, type;
2807423Sroot 	register unsigned n;
2817423Sroot 	int size;
2827423Sroot 	long bsize;
2837423Sroot 	extern int mem_no;
2847423Sroot 
2857423Sroot 	if (u.u_count == 0)
2867423Sroot 		return;
2877423Sroot 	dev = (dev_t)ip->i_rdev;
2887423Sroot 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
2897423Sroot 	    mem_no != major(dev))) {
2907423Sroot 		u.u_error = EINVAL;
2917423Sroot 		return;
2927423Sroot 	}
2937423Sroot 	ip->i_flag |= IACC;
2947423Sroot 	type = ip->i_mode&IFMT;
2957423Sroot 	if (type == IFCHR) {
2967487Skre 		register c = u.u_count;
2977722Swnj 		struct uio auio;
2987722Swnj 		struct iovec aiov;
2997722Swnj 		auio.uio_iov = &aiov;
3007722Swnj 		auio.uio_iovcnt = 1;
3017722Swnj 		aiov.iov_base = u.u_base;
3027722Swnj 		aiov.iov_len = u.u_count;
3037722Swnj 		auio.uio_offset = u.u_offset;
3047722Swnj 		auio.uio_segflg = u.u_segflg;
3057722Swnj 		auio.uio_resid = u.u_count;
3067722Swnj 		(*cdevsw[major(dev)].d_read)(dev, &auio);
3077722Swnj 		CHARGE(sc_tio * (c - auio.uio_resid));
3087722Swnj 		u.u_count = auio.uio_resid;
3097423Sroot 		return;
3107423Sroot 	}
3117423Sroot 	if (type != IFBLK) {
3127423Sroot 		dev = ip->i_dev;
3137423Sroot 		fs = ip->i_fs;
3147423Sroot 		bsize = fs->fs_bsize;
3157423Sroot 	} else
3167423Sroot 		bsize = BLKDEV_IOSIZE;
3177423Sroot 	do {
3187423Sroot 		lbn = u.u_offset / bsize;
3197423Sroot 		on = u.u_offset % bsize;
3207423Sroot 		n = MIN((unsigned)(bsize - on), u.u_count);
3217423Sroot 		if (type != IFBLK) {
3227423Sroot 			diff = ip->i_size - u.u_offset;
3237423Sroot 			if (diff <= 0)
3247423Sroot 				return;
3257423Sroot 			if (diff < n)
3267423Sroot 				n = diff;
3277423Sroot 			bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
3287423Sroot 			if (u.u_error)
3297423Sroot 				return;
3307423Sroot 			size = blksize(fs, ip, lbn);
3317423Sroot 		} else {
3327423Sroot 			size = bsize;
3337423Sroot 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
3347423Sroot 			rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
3357423Sroot 			rasize = bsize;
3367423Sroot 		}
3377423Sroot 		if ((long)bn<0) {
3387423Sroot 			bp = geteblk(size);
3397423Sroot 			clrbuf(bp);
3407423Sroot 		} else if (ip->i_lastr + 1 == lbn)
3417423Sroot 			bp = breada(dev, bn, size, rablock, rasize);
3427423Sroot 		else
3437423Sroot 			bp = bread(dev, bn, size);
3447423Sroot 		ip->i_lastr = lbn;
3457423Sroot 		n = MIN(n, size - bp->b_resid);
3467423Sroot 		if (n != 0) {
3477423Sroot 			if (u.u_segflg != 1) {
3487423Sroot 				if (copyout(bp->b_un.b_addr+on, u.u_base, n)) {
3497423Sroot 					u.u_error = EFAULT;
3507423Sroot 					goto bad;
3517423Sroot 				}
3527423Sroot 			} else
3537423Sroot 				bcopy(bp->b_un.b_addr + on, u.u_base, n);
3547423Sroot 			u.u_base += n;
3557423Sroot 			u.u_offset += n;
3567423Sroot 			u.u_count -= n;
3577423Sroot bad:
3587423Sroot 			;
3597423Sroot 		}
3607423Sroot 		if (n + on == bsize || u.u_offset == ip->i_size)
3617423Sroot 			bp->b_flags |= B_AGE;
3627423Sroot 		brelse(bp);
3637423Sroot 	} while (u.u_error == 0 && u.u_count != 0 && n != 0);
3647423Sroot }
3657423Sroot 
3667423Sroot /*
3677423Sroot  * Write the file corresponding to
3687423Sroot  * the inode pointed at by the argument.
3697423Sroot  * The actual write arguments are found
3707423Sroot  * in the variables:
3717423Sroot  *	u_base		core address for source
3727423Sroot  *	u_offset	byte offset in file
3737423Sroot  *	u_count		number of bytes to write
3747423Sroot  *	u_segflg	write to kernel/user/user I
3757423Sroot  */
3767423Sroot writei(ip)
3777423Sroot 	register struct inode *ip;
3787423Sroot {
3797423Sroot 	struct buf *bp;
3807423Sroot 	register struct fs *fs;
3817423Sroot 	dev_t dev;
3827423Sroot 	daddr_t lbn, bn;
3837423Sroot 	register int on, type;
3847423Sroot 	register unsigned n;
3857423Sroot 	long bsize;
3867423Sroot 	int size, i, count;
3877423Sroot 	extern int mem_no;
3887423Sroot 
3897423Sroot 	dev = (dev_t)ip->i_rdev;
3907423Sroot 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
3917423Sroot 	    mem_no != major(dev)) ) {
3927423Sroot 		u.u_error = EINVAL;
3937423Sroot 		return;
3947423Sroot 	}
3957423Sroot 	type = ip->i_mode & IFMT;
3967423Sroot 	if (type == IFCHR) {
3977423Sroot 		ip->i_flag |= IUPD|ICHG;
3987487Skre 		CHARGE(sc_tio * u.u_count);
3997423Sroot 		(*cdevsw[major(dev)].d_write)(dev);
4007423Sroot 		return;
4017423Sroot 	}
4027423Sroot 	if (u.u_count == 0)
4037423Sroot 		return;
4047423Sroot 	if ((ip->i_mode & IFMT) == IFREG &&
4057423Sroot 	    u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
4067423Sroot 		psignal(u.u_procp, SIGXFSZ);
4077423Sroot 		u.u_error = EMFILE;
4087423Sroot 		return;
4097423Sroot 	}
4107423Sroot 	if (type!=IFBLK) {
4117423Sroot 		dev = ip->i_dev;
4127423Sroot 		fs = ip->i_fs;
4137423Sroot 		bsize = fs->fs_bsize;
4147532Sroot 	} else
4157423Sroot 		bsize = BLKDEV_IOSIZE;
4167423Sroot 	do {
4177423Sroot 		lbn = u.u_offset / bsize;
4187423Sroot 		on = u.u_offset % bsize;
4197423Sroot 		n = MIN((unsigned)(bsize - on), u.u_count);
4207423Sroot 		if (type != IFBLK) {
4217423Sroot 			bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
4227532Sroot 			if (u.u_error || (long)bn<0)
4237423Sroot 				return;
4247423Sroot 			if(u.u_offset + n > ip->i_size &&
4257423Sroot 			   (type == IFDIR || type == IFREG || type == IFLNK))
4267423Sroot 				ip->i_size = u.u_offset + n;
4277423Sroot 			size = blksize(fs, ip, lbn);
4287423Sroot 		} else {
4297423Sroot 			size = bsize;
4307423Sroot 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
4317423Sroot 		}
4327532Sroot 		count = howmany(size, DEV_BSIZE);
4337532Sroot 		for (i = 0; i < count; i += CLSIZE)
4347532Sroot 			if (mfind(dev, bn + i))
4357532Sroot 				munhash(dev, bn + i);
4367532Sroot 		if (n == bsize)
4377423Sroot 			bp = getblk(dev, bn, size);
4387423Sroot 		else
4397423Sroot 			bp = bread(dev, bn, size);
4407423Sroot 		if (u.u_segflg != 1) {
4417423Sroot 			if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
4427423Sroot 				u.u_error = EFAULT;
4437423Sroot 				goto bad;
4447423Sroot 			}
4457423Sroot 		} else
4467423Sroot 			bcopy(u.u_base, bp->b_un.b_addr + on, n);
4477423Sroot 		u.u_base += n;
4487423Sroot 		u.u_offset += n;
4497423Sroot 		u.u_count -= n;
4507423Sroot bad:
4517423Sroot 		;
4527423Sroot 		if (u.u_error != 0)
4537423Sroot 			brelse(bp);
4547423Sroot 		else {
4557423Sroot 			if ((ip->i_mode&IFMT) == IFDIR)
4567423Sroot 				/*
4577423Sroot 				 * Writing to clear a directory entry.
4587423Sroot 				 * Must insure the write occurs before
4597423Sroot 				 * the inode is freed, or may end up
4607423Sroot 				 * pointing at a new (different) file
4617423Sroot 				 * if inode is quickly allocated again
4627423Sroot 				 * and system crashes.
4637423Sroot 				 */
4647423Sroot 				bwrite(bp);
4657423Sroot 			else if (n + on == bsize) {
4667423Sroot 				bp->b_flags |= B_AGE;
4677423Sroot 				bawrite(bp);
4687423Sroot 			} else
4697423Sroot 				bdwrite(bp);
4707423Sroot 		}
4717423Sroot 		ip->i_flag |= IUPD|ICHG;
4727423Sroot 		if (u.u_ruid != 0)
4737423Sroot 			ip->i_mode &= ~(ISUID|ISGID);
4747423Sroot 	} while (u.u_error == 0 && u.u_count != 0);
4757423Sroot }
4767423Sroot 
4777423Sroot /*
4787423Sroot  * Move n bytes at byte location
4797423Sroot  * &bp->b_un.b_addr[o] to/from (flag) the
4807423Sroot  * user/kernel (u.segflg) area starting at u.base.
4817423Sroot  * Update all the arguments by the number
4827423Sroot  * of bytes moved.
4837423Sroot  */
4847423Sroot iomove(cp, n, flag)
4857423Sroot 	register caddr_t cp;
4867423Sroot 	register unsigned n;
4877423Sroot {
4887423Sroot 	register int t;
4897423Sroot 
4907423Sroot 	if (n==0)
4917423Sroot 		return;
4927423Sroot 	if (u.u_segflg != 1) {
4937423Sroot 		if (flag==B_WRITE)
4947423Sroot 			t = copyin(u.u_base, (caddr_t)cp, n);
4957423Sroot 		else
4967423Sroot 			t = copyout((caddr_t)cp, u.u_base, n);
4977423Sroot 		if (t) {
4987423Sroot 			u.u_error = EFAULT;
4997423Sroot 			return;
5007423Sroot 		}
5017423Sroot 	} else
5027423Sroot 		if (flag == B_WRITE)
5037423Sroot 			bcopy(u.u_base, (caddr_t)cp, n);
5047423Sroot 		else
5057423Sroot 			bcopy((caddr_t)cp, u.u_base, n);
5067423Sroot 	u.u_base += n;
5077423Sroot 	u.u_offset += n;
5087423Sroot 	u.u_count -= n;
5097423Sroot }
5107714Sroot 
5117714Sroot readip(ip, uio)
5127714Sroot 	register struct inode *ip;
5137714Sroot 	register struct uio *uio;
5147714Sroot {
515*7746Sroot 	register struct iovec *iov;
5167714Sroot 	struct buf *bp;
5177714Sroot 	struct fs *fs;
5187714Sroot 	dev_t dev;
5197714Sroot 	daddr_t lbn, bn;
5207714Sroot 	off_t diff;
5217714Sroot 	register int on, type;
5227714Sroot 	register unsigned n;
5237714Sroot 	int size;
5247714Sroot 	long bsize;
5257714Sroot 	extern int mem_no;
5267714Sroot 	int error = 0;
5277714Sroot 
5287714Sroot 	dev = (dev_t)ip->i_rdev;
5297714Sroot 	if (uio->uio_offset < 0 &&
530*7746Sroot 	    ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev)))
531*7746Sroot 		return (EINVAL);
5327714Sroot 	ip->i_flag |= IACC;
5337714Sroot 	type = ip->i_mode&IFMT;
5347714Sroot 	if (type == IFCHR) {
5357714Sroot 		register c = u.u_count;
536*7746Sroot 		(*cdevsw[major(dev)].d_read)(dev, uio);
537*7746Sroot 		CHARGE(sc_tio * (c - uio->uio_resid));
538*7746Sroot 		return (u.u_error);
5397714Sroot 	}
5407714Sroot 	if (type != IFBLK) {
5417714Sroot 		dev = ip->i_dev;
5427714Sroot 		fs = ip->i_fs;
5437714Sroot 		bsize = fs->fs_bsize;
5447714Sroot 	} else
5457714Sroot 		bsize = BLKDEV_IOSIZE;
5467714Sroot nextiov:
5477714Sroot 	if (uio->uio_iovcnt == 0)
548*7746Sroot 		return (0);
549*7746Sroot 	iov = uio->uio_iov;
5507714Sroot 	if (iov->iov_len > 0)
5517714Sroot 	do {
5527714Sroot 		lbn = uio->uio_offset / bsize;
5537714Sroot 		on = uio->uio_offset % bsize;
5547714Sroot 		n = MIN((unsigned)(bsize - on), iov->iov_len);
5557714Sroot 		if (type != IFBLK) {
5567714Sroot 			diff = ip->i_size - uio->uio_offset;
5577714Sroot 			if (diff <= 0)
5587714Sroot 				return;
5597714Sroot 			if (diff < n)
5607714Sroot 				n = diff;
5617714Sroot 			bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
5627714Sroot 			if (u.u_error)
563*7746Sroot 				return (u.u_error);
5647714Sroot 			size = blksize(fs, ip, lbn);
5657714Sroot 		} else {
5667714Sroot 			size = bsize;
5677714Sroot 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
5687714Sroot 			rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
5697714Sroot 			rasize = bsize;
5707714Sroot 		}
5717714Sroot 		if ((long)bn<0) {
5727714Sroot 			bp = geteblk(size);
5737714Sroot 			clrbuf(bp);
5747714Sroot 		} else if (ip->i_lastr + 1 == lbn)
5757714Sroot 			bp = breada(dev, bn, size, rablock, rasize);
5767714Sroot 		else
5777714Sroot 			bp = bread(dev, bn, size);
5787714Sroot 		ip->i_lastr = lbn;
5797714Sroot 		n = MIN(n, size - bp->b_resid);
5807714Sroot 		if (n != 0) {
5817714Sroot 			if (uio->uio_segflg != 1) {
5827714Sroot 				if (copyout(bp->b_un.b_addr+on, iov->iov_base, n)) {
583*7746Sroot 					brelse(bp);
584*7746Sroot 					return (EFAULT);
5857714Sroot 				}
5867714Sroot 			} else
5877714Sroot 				bcopy(bp->b_un.b_addr + on, iov->iov_base, n);
5887714Sroot 			iov->iov_base += n;
5897714Sroot 			uio->uio_offset += n;
5907714Sroot 			iov->iov_len -= n;
591*7746Sroot 			uio->uio_resid -= n;
5927714Sroot 		}
5937714Sroot 		if (n + on == bsize || uio->uio_offset == ip->i_size)
5947714Sroot 			bp->b_flags |= B_AGE;
5957714Sroot 		brelse(bp);
5967714Sroot 	} while (u.u_error == 0 && iov->iov_len != 0 && n != 0);
597*7746Sroot 	if (u.u_error == 0 && iov->iov_len == 0) {
598*7746Sroot 		uio->uio_iov++;
5997714Sroot 		uio->uio_iovcnt--;
6007714Sroot 		goto nextiov;
6017714Sroot 	}
6027714Sroot 	return (error);
6037714Sroot }
604*7746Sroot 
605*7746Sroot uiomove(cp, n, dir, uio)
606*7746Sroot 	register caddr_t cp;
607*7746Sroot 	register unsigned n;
608*7746Sroot 	enum uio_direction dir;
609*7746Sroot 	struct uio *uio;
610*7746Sroot {
611*7746Sroot 	register struct iovec *iov;
612*7746Sroot 	int bad, cnt;
613*7746Sroot 
614*7746Sroot 	if (n == 0)
615*7746Sroot 		return (0);
616*7746Sroot 	if (uio->uio_segflg != 1) {
617*7746Sroot 		if (dir == UIO_READFROM)
618*7746Sroot #ifdef notdef
619*7746Sroot 			bad = copyuin(uio, (caddr_t)cp, n);
620*7746Sroot #else
621*7746Sroot 			panic("uiomove");
622*7746Sroot #endif
623*7746Sroot 		else
624*7746Sroot 			bad = copyuout((caddr_t)cp, n, uio);
625*7746Sroot 		if (bad)
626*7746Sroot 			return (EFAULT);
627*7746Sroot 	} else {
628*7746Sroot 		while (n > 0 && uio->uio_iovcnt) {
629*7746Sroot 			iov = uio->uio_iov;
630*7746Sroot 			cnt = iov->iov_len;
631*7746Sroot 			if (cnt > n)
632*7746Sroot 				cnt = n;
633*7746Sroot 			if (dir == UIO_READFROM)
634*7746Sroot 				bcopy(iov->iov_base, (caddr_t)cp, cnt);
635*7746Sroot 			else
636*7746Sroot 				bcopy((caddr_t)cp, iov->iov_base, cnt);
637*7746Sroot 			iov->iov_base += cnt;
638*7746Sroot 			iov->iov_len -= cnt;
639*7746Sroot 			uio->uio_resid -= cnt;
640*7746Sroot 			n -= cnt;
641*7746Sroot 		}
642*7746Sroot 	}
643*7746Sroot 	return (0);
644*7746Sroot }
645