xref: /csrg-svn/sys/kern/sys_generic.c (revision 7487)
1*7487Skre /*	sys_generic.c	5.2	82/07/22	*/
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"
19*7487Skre #ifdef MUSH
20*7487Skre #include "../h/quota.h"
21*7487Skre #include "../h/share.h"
22*7487Skre #else
23*7487Skre #define	CHARGE(nothing)
24*7487Skre #endif
257423Sroot 
267423Sroot /*
277423Sroot  * Read system call.
287423Sroot  */
297423Sroot read()
307423Sroot {
317423Sroot 	register struct file *fp;
327423Sroot 	register struct inode *ip;
337423Sroot 	register struct a {
347423Sroot 		int	fdes;
357423Sroot 		char	*cbuf;
367423Sroot 		unsigned count;
377423Sroot 	} *uap;
387423Sroot 
397423Sroot 	uap = (struct a *)u.u_ap;
407423Sroot 	if ((int)uap->count < 0) {
417423Sroot 		u.u_error = EINVAL;
427423Sroot 		return;
437423Sroot 	}
447423Sroot 	GETF(fp, uap->fdes);
457423Sroot 	if ((fp->f_flag&FREAD) == 0) {
467423Sroot 		u.u_error = EBADF;
477423Sroot 		return;
487423Sroot 	}
497423Sroot 	u.u_base = (caddr_t)uap->cbuf;
507423Sroot 	u.u_count = uap->count;
517423Sroot 	u.u_segflg = 0;
527423Sroot 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
537423Sroot 		if (u.u_count == uap->count)
547423Sroot 			u.u_eosys = RESTARTSYS;
557423Sroot 	} else if (fp->f_flag & FSOCKET)
567423Sroot 		u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0);
577423Sroot 	else {
587423Sroot 		ip = fp->f_inode;
597423Sroot 		u.u_offset = fp->f_offset;
607423Sroot 		if ((ip->i_mode&IFMT) == IFREG) {
617423Sroot 			ilock(ip);
627423Sroot 			readi(ip);
637423Sroot 			iunlock(ip);
647423Sroot 		} else
657423Sroot 			readi(ip);
667423Sroot 		fp->f_offset += uap->count - u.u_count;
677423Sroot 	}
687423Sroot 	u.u_r.r_val1 = uap->count - u.u_count;
697423Sroot }
707423Sroot 
717423Sroot /*
727423Sroot  * Write system call
737423Sroot  */
747423Sroot write()
757423Sroot {
767423Sroot 	register struct file *fp;
777423Sroot 	register struct inode *ip;
787423Sroot 	register struct a {
797423Sroot 		int	fdes;
807423Sroot 		char	*cbuf;
817423Sroot 		unsigned count;
827423Sroot 	} *uap;
837423Sroot 
847423Sroot 	uap = (struct a *)u.u_ap;
857423Sroot 	if ((int)uap->count < 0) {
867423Sroot 		u.u_error = EINVAL;
877423Sroot 		return;
887423Sroot 	}
897423Sroot 	GETF(fp, uap->fdes);
907423Sroot 	if ((fp->f_flag&FWRITE) == 0) {
917423Sroot 		u.u_error = EBADF;
927423Sroot 		return;
937423Sroot 	}
947423Sroot 	u.u_base = (caddr_t)uap->cbuf;
957423Sroot 	u.u_count = uap->count;
967423Sroot 	u.u_segflg = 0;
977423Sroot 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
987423Sroot 		if (u.u_count == uap->count)
997423Sroot 			u.u_eosys = RESTARTSYS;
1007423Sroot 	} else if (fp->f_flag & FSOCKET)
1017423Sroot 		u.u_error = sosend(fp->f_socket, (struct sockaddr *)0);
1027423Sroot 	else {
1037423Sroot 		ip = fp->f_inode;
1047423Sroot 		u.u_offset = fp->f_offset;
1057423Sroot 		if ((ip->i_mode&IFMT) == IFREG) {
1067423Sroot 			ilock(ip);
1077423Sroot 			writei(ip);
1087423Sroot 			iunlock(ip);
1097423Sroot 		} else
1107423Sroot 			writei(ip);
1117423Sroot 		fp->f_offset += uap->count - u.u_count;
1127423Sroot 	}
1137423Sroot 	u.u_r.r_val1 = uap->count - u.u_count;
1147423Sroot }
1157423Sroot 
1167423Sroot 
1177423Sroot /*
1187423Sroot  * Ioctl system call
1197423Sroot  * Check legality, execute common code, and switch out to individual
1207423Sroot  * device routine.
1217423Sroot  */
1227423Sroot ioctl()
1237423Sroot {
1247423Sroot 	register struct file *fp;
1257423Sroot 	register struct inode *ip;
1267423Sroot 	register struct a {
1277423Sroot 		int	fdes;
1287423Sroot 		int	cmd;
1297423Sroot 		caddr_t	cmarg;
1307423Sroot 	} *uap;
1317423Sroot 	register dev_t dev;
1327423Sroot 	register fmt;
1337423Sroot 
1347423Sroot 	uap = (struct a *)u.u_ap;
1357423Sroot 	if ((fp = getf(uap->fdes)) == NULL)
1367423Sroot 		return;
1377423Sroot 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
1387423Sroot 		u.u_error = EBADF;
1397423Sroot 		return;
1407423Sroot 	}
1417423Sroot 	if (uap->cmd==FIOCLEX) {
1427423Sroot 		u.u_pofile[uap->fdes] |= EXCLOSE;
1437423Sroot 		return;
1447423Sroot 	}
1457423Sroot 	if (uap->cmd==FIONCLEX) {
1467423Sroot 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
1477423Sroot 		return;
1487423Sroot 	}
1497423Sroot 	if (fp->f_flag & FSOCKET) {
1507423Sroot 		soioctl(fp->f_socket, uap->cmd, uap->cmarg);
1517423Sroot 		return;
1527423Sroot 	}
1537423Sroot 	ip = fp->f_inode;
1547423Sroot 	fmt = ip->i_mode & IFMT;
1557423Sroot 	if (fmt != IFCHR) {
1567423Sroot 		if (uap->cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
1577423Sroot 			off_t nread = ip->i_size - fp->f_offset;
1587423Sroot 
1597423Sroot 			if (copyout((caddr_t)&nread, uap->cmarg, sizeof(off_t)))
1607423Sroot 				u.u_error = EFAULT;
1617423Sroot 		} else if (uap->cmd == FIONBIO || uap->cmd == FIOASYNC)
1627423Sroot 			return;
1637423Sroot 		else
1647423Sroot 			u.u_error = ENOTTY;
1657423Sroot 		return;
1667423Sroot 	}
1677423Sroot 	dev = ip->i_rdev;
1687423Sroot 	u.u_r.r_val1 = 0;
1697423Sroot 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
1707423Sroot 		u.u_eosys = RESTARTSYS;
1717423Sroot 		return;
1727423Sroot 	}
1737423Sroot 	(*cdevsw[major(dev)].d_ioctl)(dev, uap->cmd, uap->cmarg, 0);
1747423Sroot }
1757423Sroot 
1767423Sroot /*
1777423Sroot  * Do nothing specific version of line
1787423Sroot  * discipline specific ioctl command.
1797423Sroot  */
1807423Sroot /*ARGSUSED*/
1817423Sroot nullioctl(tp, cmd, addr)
1827423Sroot 	struct tty *tp;
1837423Sroot 	caddr_t addr;
1847423Sroot {
1857423Sroot 
1867423Sroot 	return (cmd);
1877423Sroot }
1887423Sroot 
1897423Sroot /*
1907423Sroot  * Read the file corresponding to
1917423Sroot  * the inode pointed at by the argument.
1927423Sroot  * The actual read arguments are found
1937423Sroot  * in the variables:
1947423Sroot  *	u_base		core address for destination
1957423Sroot  *	u_offset	byte offset in file
1967423Sroot  *	u_count		number of bytes to read
1977423Sroot  *	u_segflg	read to kernel/user/user I
1987423Sroot  */
1997423Sroot readi(ip)
2007423Sroot 	register struct inode *ip;
2017423Sroot {
2027423Sroot 	struct buf *bp;
2037423Sroot 	struct fs *fs;
2047423Sroot 	dev_t dev;
2057423Sroot 	daddr_t lbn, bn;
2067423Sroot 	off_t diff;
2077423Sroot 	register int on, type;
2087423Sroot 	register unsigned n;
2097423Sroot 	int size;
2107423Sroot 	long bsize;
2117423Sroot 	extern int mem_no;
2127423Sroot 
2137423Sroot 	if (u.u_count == 0)
2147423Sroot 		return;
2157423Sroot 	dev = (dev_t)ip->i_rdev;
2167423Sroot 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
2177423Sroot 	    mem_no != major(dev))) {
2187423Sroot 		u.u_error = EINVAL;
2197423Sroot 		return;
2207423Sroot 	}
2217423Sroot 	ip->i_flag |= IACC;
2227423Sroot 	type = ip->i_mode&IFMT;
2237423Sroot 	if (type == IFCHR) {
224*7487Skre 		register c = u.u_count;
2257423Sroot 		(*cdevsw[major(dev)].d_read)(dev);
226*7487Skre 		CHARGE(sc_tio * (c - u.u_count));
2277423Sroot 		return;
2287423Sroot 	}
2297423Sroot 	if (type != IFBLK) {
2307423Sroot 		dev = ip->i_dev;
2317423Sroot 		fs = ip->i_fs;
2327423Sroot 		bsize = fs->fs_bsize;
2337423Sroot 	} else
2347423Sroot 		bsize = BLKDEV_IOSIZE;
2357423Sroot 	do {
2367423Sroot 		lbn = u.u_offset / bsize;
2377423Sroot 		on = u.u_offset % bsize;
2387423Sroot 		n = MIN((unsigned)(bsize - on), u.u_count);
2397423Sroot 		if (type != IFBLK) {
2407423Sroot 			diff = ip->i_size - u.u_offset;
2417423Sroot 			if (diff <= 0)
2427423Sroot 				return;
2437423Sroot 			if (diff < n)
2447423Sroot 				n = diff;
2457423Sroot 			bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
2467423Sroot 			if (u.u_error)
2477423Sroot 				return;
2487423Sroot 			size = blksize(fs, ip, lbn);
2497423Sroot 		} else {
2507423Sroot 			size = bsize;
2517423Sroot 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
2527423Sroot 			rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
2537423Sroot 			rasize = bsize;
2547423Sroot 		}
2557423Sroot 		if ((long)bn<0) {
2567423Sroot 			bp = geteblk(size);
2577423Sroot 			clrbuf(bp);
2587423Sroot 		} else if (ip->i_lastr + 1 == lbn)
2597423Sroot 			bp = breada(dev, bn, size, rablock, rasize);
2607423Sroot 		else
2617423Sroot 			bp = bread(dev, bn, size);
2627423Sroot 		ip->i_lastr = lbn;
2637423Sroot 		n = MIN(n, size - bp->b_resid);
2647423Sroot 		if (n != 0) {
2657423Sroot #ifdef UNFAST
2667423Sroot 			iomove(bp->b_un.b_addr + on, n, B_READ);
2677423Sroot #else
2687423Sroot 			if (u.u_segflg != 1) {
2697423Sroot 				if (copyout(bp->b_un.b_addr+on, u.u_base, n)) {
2707423Sroot 					u.u_error = EFAULT;
2717423Sroot 					goto bad;
2727423Sroot 				}
2737423Sroot 			} else
2747423Sroot 				bcopy(bp->b_un.b_addr + on, u.u_base, n);
2757423Sroot 			u.u_base += n;
2767423Sroot 			u.u_offset += n;
2777423Sroot 			u.u_count -= n;
2787423Sroot bad:
2797423Sroot 			;
2807423Sroot #endif
2817423Sroot 		}
2827423Sroot 		if (n + on == bsize || u.u_offset == ip->i_size)
2837423Sroot 			bp->b_flags |= B_AGE;
2847423Sroot 		brelse(bp);
2857423Sroot 	} while (u.u_error == 0 && u.u_count != 0 && n != 0);
2867423Sroot }
2877423Sroot 
2887423Sroot /*
2897423Sroot  * Write the file corresponding to
2907423Sroot  * the inode pointed at by the argument.
2917423Sroot  * The actual write arguments are found
2927423Sroot  * in the variables:
2937423Sroot  *	u_base		core address for source
2947423Sroot  *	u_offset	byte offset in file
2957423Sroot  *	u_count		number of bytes to write
2967423Sroot  *	u_segflg	write to kernel/user/user I
2977423Sroot  */
2987423Sroot writei(ip)
2997423Sroot 	register struct inode *ip;
3007423Sroot {
3017423Sroot 	struct buf *bp;
3027423Sroot 	register struct fs *fs;
3037423Sroot 	dev_t dev;
3047423Sroot 	daddr_t lbn, bn;
3057423Sroot 	register int on, type;
3067423Sroot 	register unsigned n;
3077423Sroot 	long bsize;
3087423Sroot 	int size, i, count;
3097423Sroot 	extern int mem_no;
3107423Sroot 
3117423Sroot 	dev = (dev_t)ip->i_rdev;
3127423Sroot 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
3137423Sroot 	    mem_no != major(dev)) ) {
3147423Sroot 		u.u_error = EINVAL;
3157423Sroot 		return;
3167423Sroot 	}
3177423Sroot 	type = ip->i_mode & IFMT;
3187423Sroot 	if (type == IFCHR) {
3197423Sroot 		ip->i_flag |= IUPD|ICHG;
320*7487Skre 		CHARGE(sc_tio * u.u_count);
3217423Sroot 		(*cdevsw[major(dev)].d_write)(dev);
3227423Sroot 		return;
3237423Sroot 	}
3247423Sroot 	if (u.u_count == 0)
3257423Sroot 		return;
3267423Sroot 	if ((ip->i_mode & IFMT) == IFREG &&
3277423Sroot 	    u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
3287423Sroot 		psignal(u.u_procp, SIGXFSZ);
3297423Sroot 		u.u_error = EMFILE;
3307423Sroot 		return;
3317423Sroot 	}
3327423Sroot 	if (type!=IFBLK) {
3337423Sroot 		dev = ip->i_dev;
3347423Sroot 		fs = ip->i_fs;
3357423Sroot 		bsize = fs->fs_bsize;
3367423Sroot 	} else {
3377423Sroot 		bsize = BLKDEV_IOSIZE;
3387423Sroot 	}
3397423Sroot 	do {
3407423Sroot 		lbn = u.u_offset / bsize;
3417423Sroot 		on = u.u_offset % bsize;
3427423Sroot 		n = MIN((unsigned)(bsize - on), u.u_count);
3437423Sroot 		if (type != IFBLK) {
3447423Sroot 			bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
3457423Sroot 			if ((long)bn<0)
3467423Sroot 				return;
3477423Sroot 			if(u.u_offset + n > ip->i_size &&
3487423Sroot 			   (type == IFDIR || type == IFREG || type == IFLNK))
3497423Sroot 				ip->i_size = u.u_offset + n;
3507423Sroot 			size = blksize(fs, ip, lbn);
3517423Sroot 		} else {
3527423Sroot 			size = bsize;
3537423Sroot 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
3547423Sroot 		}
3557423Sroot 		if (bn) {
3567423Sroot 			count = howmany(size, DEV_BSIZE);
3577423Sroot 			for (i = 0; i < count; i += CLSIZE) {
3587423Sroot 				if (mfind(dev, bn + i))
3597423Sroot 					munhash(dev, bn + i);
3607423Sroot 			}
3617423Sroot 		}
3627423Sroot 		if(n == bsize)
3637423Sroot 			bp = getblk(dev, bn, size);
3647423Sroot 		else
3657423Sroot 			bp = bread(dev, bn, size);
3667423Sroot #ifdef UNFAST
3677423Sroot 		iomove(bp->b_un.b_addr + on, n, B_WRITE);
3687423Sroot #else
3697423Sroot 		if (u.u_segflg != 1) {
3707423Sroot 			if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
3717423Sroot 				u.u_error = EFAULT;
3727423Sroot 				goto bad;
3737423Sroot 			}
3747423Sroot 		} else
3757423Sroot 			bcopy(u.u_base, bp->b_un.b_addr + on, n);
3767423Sroot 		u.u_base += n;
3777423Sroot 		u.u_offset += n;
3787423Sroot 		u.u_count -= n;
3797423Sroot bad:
3807423Sroot 		;
3817423Sroot #endif
3827423Sroot 		if (u.u_error != 0)
3837423Sroot 			brelse(bp);
3847423Sroot 		else {
3857423Sroot 			if ((ip->i_mode&IFMT) == IFDIR)
3867423Sroot 				/*
3877423Sroot 				 * Writing to clear a directory entry.
3887423Sroot 				 * Must insure the write occurs before
3897423Sroot 				 * the inode is freed, or may end up
3907423Sroot 				 * pointing at a new (different) file
3917423Sroot 				 * if inode is quickly allocated again
3927423Sroot 				 * and system crashes.
3937423Sroot 				 */
3947423Sroot 				bwrite(bp);
3957423Sroot 			else if (n + on == bsize) {
3967423Sroot 				bp->b_flags |= B_AGE;
3977423Sroot 				bawrite(bp);
3987423Sroot 			} else
3997423Sroot 				bdwrite(bp);
4007423Sroot 		}
4017423Sroot 		ip->i_flag |= IUPD|ICHG;
4027423Sroot 		if (u.u_ruid != 0)
4037423Sroot 			ip->i_mode &= ~(ISUID|ISGID);
4047423Sroot 	} while (u.u_error == 0 && u.u_count != 0);
4057423Sroot }
4067423Sroot 
4077423Sroot /*
4087423Sroot  * Move n bytes at byte location
4097423Sroot  * &bp->b_un.b_addr[o] to/from (flag) the
4107423Sroot  * user/kernel (u.segflg) area starting at u.base.
4117423Sroot  * Update all the arguments by the number
4127423Sroot  * of bytes moved.
4137423Sroot  */
4147423Sroot iomove(cp, n, flag)
4157423Sroot 	register caddr_t cp;
4167423Sroot 	register unsigned n;
4177423Sroot {
4187423Sroot 	register int t;
4197423Sroot 
4207423Sroot 	if (n==0)
4217423Sroot 		return;
4227423Sroot 	if (u.u_segflg != 1) {
4237423Sroot 		if (flag==B_WRITE)
4247423Sroot 			t = copyin(u.u_base, (caddr_t)cp, n);
4257423Sroot 		else
4267423Sroot 			t = copyout((caddr_t)cp, u.u_base, n);
4277423Sroot 		if (t) {
4287423Sroot 			u.u_error = EFAULT;
4297423Sroot 			return;
4307423Sroot 		}
4317423Sroot 	} else
4327423Sroot 		if (flag == B_WRITE)
4337423Sroot 			bcopy(u.u_base, (caddr_t)cp, n);
4347423Sroot 		else
4357423Sroot 			bcopy((caddr_t)cp, u.u_base, n);
4367423Sroot 	u.u_base += n;
4377423Sroot 	u.u_offset += n;
4387423Sroot 	u.u_count -= n;
4397423Sroot }
440