xref: /csrg-svn/sys/kern/sys_generic.c (revision 7624)
1*7624Ssam /*	sys_generic.c	5.5	82/08/01	*/
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"
87500Sroot #include "../h/fcntl.h"
97423Sroot #include "../h/file.h"
107423Sroot #include "../h/inode.h"
117423Sroot #include "../h/buf.h"
127423Sroot #include "../h/proc.h"
137423Sroot #include "../h/inline.h"
147423Sroot #include "../h/conf.h"
157423Sroot #include "../h/socket.h"
167423Sroot #include "../h/socketvar.h"
177423Sroot #include "../h/cmap.h"
187423Sroot #include "../h/vlimit.h"
197423Sroot #include "../h/fs.h"
207487Skre #ifdef MUSH
217487Skre #include "../h/quota.h"
227487Skre #include "../h/share.h"
237487Skre #else
247487Skre #define	CHARGE(nothing)
257487Skre #endif
267500Sroot #include "../h/descrip.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;
407423Sroot 
417423Sroot 	uap = (struct a *)u.u_ap;
427423Sroot 	if ((int)uap->count < 0) {
437423Sroot 		u.u_error = EINVAL;
447423Sroot 		return;
457423Sroot 	}
467423Sroot 	GETF(fp, uap->fdes);
477423Sroot 	if ((fp->f_flag&FREAD) == 0) {
487423Sroot 		u.u_error = EBADF;
497423Sroot 		return;
507423Sroot 	}
517423Sroot 	u.u_base = (caddr_t)uap->cbuf;
527423Sroot 	u.u_count = uap->count;
537423Sroot 	u.u_segflg = 0;
547423Sroot 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
557423Sroot 		if (u.u_count == uap->count)
567423Sroot 			u.u_eosys = RESTARTSYS;
577500Sroot 	} else if (fp->f_type == DTYPE_SOCKET)
587423Sroot 		u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0);
597423Sroot 	else {
607423Sroot 		ip = fp->f_inode;
617423Sroot 		u.u_offset = fp->f_offset;
627423Sroot 		if ((ip->i_mode&IFMT) == IFREG) {
637423Sroot 			ilock(ip);
647423Sroot 			readi(ip);
657423Sroot 			iunlock(ip);
667423Sroot 		} else
677423Sroot 			readi(ip);
687423Sroot 		fp->f_offset += uap->count - u.u_count;
697423Sroot 	}
707423Sroot 	u.u_r.r_val1 = uap->count - u.u_count;
717423Sroot }
727423Sroot 
737423Sroot /*
747423Sroot  * Write system call
757423Sroot  */
767423Sroot write()
777423Sroot {
787423Sroot 	register struct file *fp;
797423Sroot 	register struct inode *ip;
807423Sroot 	register struct a {
817423Sroot 		int	fdes;
827423Sroot 		char	*cbuf;
837423Sroot 		unsigned count;
847423Sroot 	} *uap;
857423Sroot 
867423Sroot 	uap = (struct a *)u.u_ap;
877423Sroot 	if ((int)uap->count < 0) {
887423Sroot 		u.u_error = EINVAL;
897423Sroot 		return;
907423Sroot 	}
917423Sroot 	GETF(fp, uap->fdes);
927423Sroot 	if ((fp->f_flag&FWRITE) == 0) {
937423Sroot 		u.u_error = EBADF;
947423Sroot 		return;
957423Sroot 	}
967423Sroot 	u.u_base = (caddr_t)uap->cbuf;
977423Sroot 	u.u_count = uap->count;
987423Sroot 	u.u_segflg = 0;
997423Sroot 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
1007423Sroot 		if (u.u_count == uap->count)
1017423Sroot 			u.u_eosys = RESTARTSYS;
1027500Sroot 	} else if (fp->f_type == DTYPE_SOCKET)
1037423Sroot 		u.u_error = sosend(fp->f_socket, (struct sockaddr *)0);
1047423Sroot 	else {
1057423Sroot 		ip = fp->f_inode;
1067500Sroot 		if (fp->f_flag & O_APPEND)
1077500Sroot 			fp->f_offset = ip->i_size;
1087423Sroot 		u.u_offset = fp->f_offset;
1097423Sroot 		if ((ip->i_mode&IFMT) == IFREG) {
1107423Sroot 			ilock(ip);
1117423Sroot 			writei(ip);
1127423Sroot 			iunlock(ip);
1137423Sroot 		} else
1147423Sroot 			writei(ip);
1157423Sroot 		fp->f_offset += uap->count - u.u_count;
1167423Sroot 	}
1177423Sroot 	u.u_r.r_val1 = uap->count - u.u_count;
1187423Sroot }
1197423Sroot 
1207500Sroot readv()
1217500Sroot {
1227423Sroot 
1237500Sroot }
1247500Sroot 
1257500Sroot writev()
1267500Sroot {
1277500Sroot 
1287500Sroot }
1297500Sroot 
1307423Sroot /*
1317423Sroot  * Ioctl system call
132*7624Ssam  * Check legality, execute common code,
133*7624Ssam  * and switch out to individual device routine.
1347423Sroot  */
1357423Sroot ioctl()
1367423Sroot {
1377423Sroot 	register struct file *fp;
138*7624Ssam 	struct a {
1397423Sroot 		int	fdes;
1407423Sroot 		int	cmd;
1417423Sroot 		caddr_t	cmarg;
1427423Sroot 	} *uap;
143*7624Ssam 	register int com, size;
144*7624Ssam 	char data[IOCPARM_MASK+1];
1457423Sroot 
1467423Sroot 	uap = (struct a *)u.u_ap;
1477423Sroot 	if ((fp = getf(uap->fdes)) == NULL)
1487423Sroot 		return;
1497423Sroot 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
1507423Sroot 		u.u_error = EBADF;
1517423Sroot 		return;
1527423Sroot 	}
153*7624Ssam 	com = uap->cmd;
154*7624Ssam 
155*7624Ssam #ifndef ONLYNEWIOCTLS
156*7624Ssam 	/*
157*7624Ssam 	 * Map old style ioctl's into new for the
158*7624Ssam 	 * sake of backwards compatibility (sigh).
159*7624Ssam 	 */
160*7624Ssam 	if ((com&~0xffff) == 0) {
161*7624Ssam 		com = mapioctl(com);
162*7624Ssam 		if (com == 0) {
163*7624Ssam 			u.u_error = EINVAL;
164*7624Ssam 			return;
165*7624Ssam 		}
166*7624Ssam 	}
167*7624Ssam #endif
168*7624Ssam 	if (com == FIOCLEX) {
1697423Sroot 		u.u_pofile[uap->fdes] |= EXCLOSE;
1707423Sroot 		return;
1717423Sroot 	}
172*7624Ssam 	if (com == FIONCLEX) {
1737423Sroot 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
1747423Sroot 		return;
1757423Sroot 	}
176*7624Ssam 
177*7624Ssam 	/*
178*7624Ssam 	 * Interpret high order word to find
179*7624Ssam 	 * amount of data to be copied to/from the
180*7624Ssam 	 * user's address space.
181*7624Ssam 	 * (this'll have to change if we have in+out ioctls)
182*7624Ssam 	 */
183*7624Ssam 	size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
184*7624Ssam 	if (size > sizeof (data)) {
185*7624Ssam 		u.u_error = EFAULT;
1867423Sroot 		return;
1877423Sroot 	}
188*7624Ssam 	if ((com&IOC_IN) && size) {
189*7624Ssam 		if (copyin(uap->cmarg, (caddr_t)data, size)) {
190*7624Ssam 			u.u_error = EFAULT;
191*7624Ssam 			return;
192*7624Ssam 		}
193*7624Ssam 	} else
194*7624Ssam 		*(caddr_t *)data = uap->cmarg;
195*7624Ssam 	/*
196*7624Ssam 	 * Zero the buffer on the stack so the user
197*7624Ssam 	 * always gets back something deterministic.
198*7624Ssam 	 */
199*7624Ssam 	if ((com&IOC_OUT) && size)
200*7624Ssam 		bzero((caddr_t)data, size);
2017423Sroot 
202*7624Ssam 	if (fp->f_type == DTYPE_SOCKET)
203*7624Ssam 		soioctl(fp->f_socket, com, data);
204*7624Ssam 	else {
205*7624Ssam 		register struct inode *ip = fp->f_inode;
206*7624Ssam 		int fmt = ip->i_mode & IFMT;
207*7624Ssam 		dev_t dev;
208*7624Ssam 
209*7624Ssam 		if (fmt != IFCHR) {
210*7624Ssam 			if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
211*7624Ssam 				*(off_t *)data = ip->i_size - fp->f_offset;
212*7624Ssam 				goto returndata;
213*7624Ssam 			}
214*7624Ssam 			if (com != FIONBIO && com != FIOASYNC)
215*7624Ssam 				u.u_error = ENOTTY;
2167423Sroot 			return;
217*7624Ssam 		}
218*7624Ssam 		dev = ip->i_rdev;
219*7624Ssam 		u.u_r.r_val1 = 0;
220*7624Ssam 		if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
221*7624Ssam 			u.u_eosys = RESTARTSYS;
222*7624Ssam 			return;
223*7624Ssam 		}
224*7624Ssam 		(*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0);
2257423Sroot 	}
226*7624Ssam 
227*7624Ssam returndata:
228*7624Ssam 	/*
229*7624Ssam 	 * Copy any data to user, size was
230*7624Ssam 	 * already set and checked above.
231*7624Ssam 	 */
232*7624Ssam 	if ((com&IOC_OUT) && size && copyout(data, uap->cmarg, size))
233*7624Ssam 		u.u_error = EFAULT;
2347423Sroot }
2357423Sroot 
2367423Sroot /*
2377423Sroot  * Do nothing specific version of line
2387423Sroot  * discipline specific ioctl command.
2397423Sroot  */
2407423Sroot /*ARGSUSED*/
241*7624Ssam nullioctl(tp, cmd, data, flags)
2427423Sroot 	struct tty *tp;
243*7624Ssam 	char *data;
244*7624Ssam 	int flags;
2457423Sroot {
2467423Sroot 
247*7624Ssam #ifdef lint
248*7624Ssam 	tp = tp; data = data; flags = flags;
249*7624Ssam #endif
2507423Sroot 	return (cmd);
2517423Sroot }
2527423Sroot 
2537423Sroot /*
2547423Sroot  * Read the file corresponding to
2557423Sroot  * the inode pointed at by the argument.
2567423Sroot  * The actual read arguments are found
2577423Sroot  * in the variables:
2587423Sroot  *	u_base		core address for destination
2597423Sroot  *	u_offset	byte offset in file
2607423Sroot  *	u_count		number of bytes to read
2617423Sroot  *	u_segflg	read to kernel/user/user I
2627423Sroot  */
2637423Sroot readi(ip)
2647423Sroot 	register struct inode *ip;
2657423Sroot {
2667423Sroot 	struct buf *bp;
2677423Sroot 	struct fs *fs;
2687423Sroot 	dev_t dev;
2697423Sroot 	daddr_t lbn, bn;
2707423Sroot 	off_t diff;
2717423Sroot 	register int on, type;
2727423Sroot 	register unsigned n;
2737423Sroot 	int size;
2747423Sroot 	long bsize;
2757423Sroot 	extern int mem_no;
2767423Sroot 
2777423Sroot 	if (u.u_count == 0)
2787423Sroot 		return;
2797423Sroot 	dev = (dev_t)ip->i_rdev;
2807423Sroot 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
2817423Sroot 	    mem_no != major(dev))) {
2827423Sroot 		u.u_error = EINVAL;
2837423Sroot 		return;
2847423Sroot 	}
2857423Sroot 	ip->i_flag |= IACC;
2867423Sroot 	type = ip->i_mode&IFMT;
2877423Sroot 	if (type == IFCHR) {
2887487Skre 		register c = u.u_count;
2897423Sroot 		(*cdevsw[major(dev)].d_read)(dev);
2907487Skre 		CHARGE(sc_tio * (c - u.u_count));
2917423Sroot 		return;
2927423Sroot 	}
2937423Sroot 	if (type != IFBLK) {
2947423Sroot 		dev = ip->i_dev;
2957423Sroot 		fs = ip->i_fs;
2967423Sroot 		bsize = fs->fs_bsize;
2977423Sroot 	} else
2987423Sroot 		bsize = BLKDEV_IOSIZE;
2997423Sroot 	do {
3007423Sroot 		lbn = u.u_offset / bsize;
3017423Sroot 		on = u.u_offset % bsize;
3027423Sroot 		n = MIN((unsigned)(bsize - on), u.u_count);
3037423Sroot 		if (type != IFBLK) {
3047423Sroot 			diff = ip->i_size - u.u_offset;
3057423Sroot 			if (diff <= 0)
3067423Sroot 				return;
3077423Sroot 			if (diff < n)
3087423Sroot 				n = diff;
3097423Sroot 			bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
3107423Sroot 			if (u.u_error)
3117423Sroot 				return;
3127423Sroot 			size = blksize(fs, ip, lbn);
3137423Sroot 		} else {
3147423Sroot 			size = bsize;
3157423Sroot 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
3167423Sroot 			rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
3177423Sroot 			rasize = bsize;
3187423Sroot 		}
3197423Sroot 		if ((long)bn<0) {
3207423Sroot 			bp = geteblk(size);
3217423Sroot 			clrbuf(bp);
3227423Sroot 		} else if (ip->i_lastr + 1 == lbn)
3237423Sroot 			bp = breada(dev, bn, size, rablock, rasize);
3247423Sroot 		else
3257423Sroot 			bp = bread(dev, bn, size);
3267423Sroot 		ip->i_lastr = lbn;
3277423Sroot 		n = MIN(n, size - bp->b_resid);
3287423Sroot 		if (n != 0) {
3297423Sroot #ifdef UNFAST
3307423Sroot 			iomove(bp->b_un.b_addr + on, n, B_READ);
3317423Sroot #else
3327423Sroot 			if (u.u_segflg != 1) {
3337423Sroot 				if (copyout(bp->b_un.b_addr+on, u.u_base, n)) {
3347423Sroot 					u.u_error = EFAULT;
3357423Sroot 					goto bad;
3367423Sroot 				}
3377423Sroot 			} else
3387423Sroot 				bcopy(bp->b_un.b_addr + on, u.u_base, n);
3397423Sroot 			u.u_base += n;
3407423Sroot 			u.u_offset += n;
3417423Sroot 			u.u_count -= n;
3427423Sroot bad:
3437423Sroot 			;
3447423Sroot #endif
3457423Sroot 		}
3467423Sroot 		if (n + on == bsize || u.u_offset == ip->i_size)
3477423Sroot 			bp->b_flags |= B_AGE;
3487423Sroot 		brelse(bp);
3497423Sroot 	} while (u.u_error == 0 && u.u_count != 0 && n != 0);
3507423Sroot }
3517423Sroot 
3527423Sroot /*
3537423Sroot  * Write the file corresponding to
3547423Sroot  * the inode pointed at by the argument.
3557423Sroot  * The actual write arguments are found
3567423Sroot  * in the variables:
3577423Sroot  *	u_base		core address for source
3587423Sroot  *	u_offset	byte offset in file
3597423Sroot  *	u_count		number of bytes to write
3607423Sroot  *	u_segflg	write to kernel/user/user I
3617423Sroot  */
3627423Sroot writei(ip)
3637423Sroot 	register struct inode *ip;
3647423Sroot {
3657423Sroot 	struct buf *bp;
3667423Sroot 	register struct fs *fs;
3677423Sroot 	dev_t dev;
3687423Sroot 	daddr_t lbn, bn;
3697423Sroot 	register int on, type;
3707423Sroot 	register unsigned n;
3717423Sroot 	long bsize;
3727423Sroot 	int size, i, count;
3737423Sroot 	extern int mem_no;
3747423Sroot 
3757423Sroot 	dev = (dev_t)ip->i_rdev;
3767423Sroot 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
3777423Sroot 	    mem_no != major(dev)) ) {
3787423Sroot 		u.u_error = EINVAL;
3797423Sroot 		return;
3807423Sroot 	}
3817423Sroot 	type = ip->i_mode & IFMT;
3827423Sroot 	if (type == IFCHR) {
3837423Sroot 		ip->i_flag |= IUPD|ICHG;
3847487Skre 		CHARGE(sc_tio * u.u_count);
3857423Sroot 		(*cdevsw[major(dev)].d_write)(dev);
3867423Sroot 		return;
3877423Sroot 	}
3887423Sroot 	if (u.u_count == 0)
3897423Sroot 		return;
3907423Sroot 	if ((ip->i_mode & IFMT) == IFREG &&
3917423Sroot 	    u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
3927423Sroot 		psignal(u.u_procp, SIGXFSZ);
3937423Sroot 		u.u_error = EMFILE;
3947423Sroot 		return;
3957423Sroot 	}
3967423Sroot 	if (type!=IFBLK) {
3977423Sroot 		dev = ip->i_dev;
3987423Sroot 		fs = ip->i_fs;
3997423Sroot 		bsize = fs->fs_bsize;
4007532Sroot 	} else
4017423Sroot 		bsize = BLKDEV_IOSIZE;
4027423Sroot 	do {
4037423Sroot 		lbn = u.u_offset / bsize;
4047423Sroot 		on = u.u_offset % bsize;
4057423Sroot 		n = MIN((unsigned)(bsize - on), u.u_count);
4067423Sroot 		if (type != IFBLK) {
4077423Sroot 			bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
4087532Sroot 			if (u.u_error || (long)bn<0)
4097423Sroot 				return;
4107423Sroot 			if(u.u_offset + n > ip->i_size &&
4117423Sroot 			   (type == IFDIR || type == IFREG || type == IFLNK))
4127423Sroot 				ip->i_size = u.u_offset + n;
4137423Sroot 			size = blksize(fs, ip, lbn);
4147423Sroot 		} else {
4157423Sroot 			size = bsize;
4167423Sroot 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
4177423Sroot 		}
4187532Sroot 		count = howmany(size, DEV_BSIZE);
4197532Sroot 		for (i = 0; i < count; i += CLSIZE)
4207532Sroot 			if (mfind(dev, bn + i))
4217532Sroot 				munhash(dev, bn + i);
4227532Sroot 		if (n == bsize)
4237423Sroot 			bp = getblk(dev, bn, size);
4247423Sroot 		else
4257423Sroot 			bp = bread(dev, bn, size);
4267423Sroot #ifdef UNFAST
4277423Sroot 		iomove(bp->b_un.b_addr + on, n, B_WRITE);
4287423Sroot #else
4297423Sroot 		if (u.u_segflg != 1) {
4307423Sroot 			if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
4317423Sroot 				u.u_error = EFAULT;
4327423Sroot 				goto bad;
4337423Sroot 			}
4347423Sroot 		} else
4357423Sroot 			bcopy(u.u_base, bp->b_un.b_addr + on, n);
4367423Sroot 		u.u_base += n;
4377423Sroot 		u.u_offset += n;
4387423Sroot 		u.u_count -= n;
4397423Sroot bad:
4407423Sroot 		;
4417423Sroot #endif
4427423Sroot 		if (u.u_error != 0)
4437423Sroot 			brelse(bp);
4447423Sroot 		else {
4457423Sroot 			if ((ip->i_mode&IFMT) == IFDIR)
4467423Sroot 				/*
4477423Sroot 				 * Writing to clear a directory entry.
4487423Sroot 				 * Must insure the write occurs before
4497423Sroot 				 * the inode is freed, or may end up
4507423Sroot 				 * pointing at a new (different) file
4517423Sroot 				 * if inode is quickly allocated again
4527423Sroot 				 * and system crashes.
4537423Sroot 				 */
4547423Sroot 				bwrite(bp);
4557423Sroot 			else if (n + on == bsize) {
4567423Sroot 				bp->b_flags |= B_AGE;
4577423Sroot 				bawrite(bp);
4587423Sroot 			} else
4597423Sroot 				bdwrite(bp);
4607423Sroot 		}
4617423Sroot 		ip->i_flag |= IUPD|ICHG;
4627423Sroot 		if (u.u_ruid != 0)
4637423Sroot 			ip->i_mode &= ~(ISUID|ISGID);
4647423Sroot 	} while (u.u_error == 0 && u.u_count != 0);
4657423Sroot }
4667423Sroot 
4677423Sroot /*
4687423Sroot  * Move n bytes at byte location
4697423Sroot  * &bp->b_un.b_addr[o] to/from (flag) the
4707423Sroot  * user/kernel (u.segflg) area starting at u.base.
4717423Sroot  * Update all the arguments by the number
4727423Sroot  * of bytes moved.
4737423Sroot  */
4747423Sroot iomove(cp, n, flag)
4757423Sroot 	register caddr_t cp;
4767423Sroot 	register unsigned n;
4777423Sroot {
4787423Sroot 	register int t;
4797423Sroot 
4807423Sroot 	if (n==0)
4817423Sroot 		return;
4827423Sroot 	if (u.u_segflg != 1) {
4837423Sroot 		if (flag==B_WRITE)
4847423Sroot 			t = copyin(u.u_base, (caddr_t)cp, n);
4857423Sroot 		else
4867423Sroot 			t = copyout((caddr_t)cp, u.u_base, n);
4877423Sroot 		if (t) {
4887423Sroot 			u.u_error = EFAULT;
4897423Sroot 			return;
4907423Sroot 		}
4917423Sroot 	} else
4927423Sroot 		if (flag == B_WRITE)
4937423Sroot 			bcopy(u.u_base, (caddr_t)cp, n);
4947423Sroot 		else
4957423Sroot 			bcopy((caddr_t)cp, u.u_base, n);
4967423Sroot 	u.u_base += n;
4977423Sroot 	u.u_offset += n;
4987423Sroot 	u.u_count -= n;
4997423Sroot }
500