xref: /csrg-svn/sys/kern/sys_generic.c (revision 7746)
1 /*	sys_generic.c	5.9	82/08/14	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/dir.h"
6 #include "../h/user.h"
7 #include "../h/tty.h"
8 #include "../h/file.h"
9 #include "../h/inode.h"
10 #include "../h/buf.h"
11 #include "../h/proc.h"
12 #include "../h/inline.h"
13 #include "../h/conf.h"
14 #include "../h/socket.h"
15 #include "../h/socketvar.h"
16 #include "../h/cmap.h"
17 #include "../h/vlimit.h"
18 #include "../h/fs.h"
19 #ifdef MUSH
20 #include "../h/quota.h"
21 #include "../h/share.h"
22 #else
23 #define	CHARGE(nothing)
24 #endif
25 #include "../h/descrip.h"
26 #include "../h/uio.h"
27 
28 /*
29  * Read system call.
30  */
31 read()
32 {
33 	register struct file *fp;
34 	register struct inode *ip;
35 	register struct a {
36 		int	fdes;
37 		char	*cbuf;
38 		unsigned count;
39 	} *uap;
40 	struct uio auio;
41 	struct iovec aiov;
42 
43 	uap = (struct a *)u.u_ap;
44 	if ((int)uap->count < 0) {
45 		u.u_error = EINVAL;
46 		return;
47 	}
48 	GETF(fp, uap->fdes);
49 	if ((fp->f_flag&FREAD) == 0) {
50 		u.u_error = EBADF;
51 		return;
52 	}
53 	aiov.iov_base = (caddr_t)uap->cbuf;
54 	aiov.iov_len = uap->count;
55 	auio.uio_iov = &aiov;
56 	auio.uio_iovcnt = 1;
57 	auio.uio_segflg = 0;
58 	auio.uio_resid = uap->count;
59 	u.u_base = (caddr_t)0xc0000000;
60 	u.u_count = 0x40000000;
61 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
62 		if (auio.uio_resid == uap->count)
63 			u.u_eosys = RESTARTSYS;
64 	} else if (fp->f_type == DTYPE_SOCKET)
65 		u.u_error = soreceive(fp->f_socket, (struct sockaddr *)0, &auio);
66 	else {
67 		ip = fp->f_inode;
68 		auio.uio_offset = fp->f_offset;
69 		if ((ip->i_mode&IFMT) == IFREG) {
70 			ilock(ip);
71 			u.u_error = readip(ip, &auio);
72 			iunlock(ip);
73 		} else
74 			u.u_error = readip(ip, &auio);
75 		fp->f_offset += uap->count - auio.uio_resid;
76 	}
77 	u.u_r.r_val1 = uap->count - auio.uio_resid;
78 }
79 
80 /*
81  * Write system call
82  */
83 write()
84 {
85 	register struct file *fp;
86 	register struct inode *ip;
87 	register struct a {
88 		int	fdes;
89 		char	*cbuf;
90 		unsigned count;
91 	} *uap;
92 
93 	uap = (struct a *)u.u_ap;
94 	if ((int)uap->count < 0) {
95 		u.u_error = EINVAL;
96 		return;
97 	}
98 	GETF(fp, uap->fdes);
99 	if ((fp->f_flag&FWRITE) == 0) {
100 		u.u_error = EBADF;
101 		return;
102 	}
103 	u.u_base = (caddr_t)uap->cbuf;
104 	u.u_count = uap->count;
105 	u.u_segflg = 0;
106 	if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
107 		if (u.u_count == uap->count)
108 			u.u_eosys = RESTARTSYS;
109 	} else if (fp->f_type == DTYPE_SOCKET)
110 		u.u_error = sosend(fp->f_socket, (struct sockaddr *)0);
111 	else {
112 		ip = fp->f_inode;
113 		if (fp->f_flag&FAPPEND)
114 			fp->f_offset = ip->i_size;
115 		u.u_offset = fp->f_offset;
116 		if ((ip->i_mode&IFMT) == IFREG) {
117 			ilock(ip);
118 			writei(ip);
119 			iunlock(ip);
120 		} else
121 			writei(ip);
122 		fp->f_offset += uap->count - u.u_count;
123 	}
124 	u.u_r.r_val1 = uap->count - u.u_count;
125 }
126 
127 readv()
128 {
129 
130 }
131 
132 writev()
133 {
134 
135 }
136 
137 /*
138  * Ioctl system call
139  * Check legality, execute common code,
140  * and switch out to individual device routine.
141  */
142 ioctl()
143 {
144 	register struct file *fp;
145 	struct a {
146 		int	fdes;
147 		int	cmd;
148 		caddr_t	cmarg;
149 	} *uap;
150 	register int com, size;
151 	char data[IOCPARM_MASK+1];
152 
153 	uap = (struct a *)u.u_ap;
154 	if ((fp = getf(uap->fdes)) == NULL)
155 		return;
156 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
157 		u.u_error = EBADF;
158 		return;
159 	}
160 	com = uap->cmd;
161 
162 #ifndef NOCOMPAT
163 	/*
164 	 * Map old style ioctl's into new for the
165 	 * sake of backwards compatibility (sigh).
166 	 */
167 	if ((com&~0xffff) == 0) {
168 		com = mapioctl(com);
169 		if (com == 0) {
170 			u.u_error = EINVAL;
171 			return;
172 		}
173 	}
174 #endif
175 	if (com == FIOCLEX) {
176 		u.u_pofile[uap->fdes] |= EXCLOSE;
177 		return;
178 	}
179 	if (com == FIONCLEX) {
180 		u.u_pofile[uap->fdes] &= ~EXCLOSE;
181 		return;
182 	}
183 
184 	/*
185 	 * Interpret high order word to find
186 	 * amount of data to be copied to/from the
187 	 * user's address space.
188 	 * (this'll have to change if we have in+out ioctls)
189 	 */
190 	size = (com &~ (IOC_INOUT|IOC_VOID)) >> 16;
191 	if (size > sizeof (data)) {
192 		u.u_error = EFAULT;
193 		return;
194 	}
195 	if (com&IOC_IN && size) {
196 		if (copyin(uap->cmarg, (caddr_t)data, size)) {
197 			u.u_error = EFAULT;
198 			return;
199 		}
200 	} else
201 		*(caddr_t *)data = uap->cmarg;
202 	/*
203 	 * Zero the buffer on the stack so the user
204 	 * always gets back something deterministic.
205 	 */
206 	if ((com&IOC_OUT) && size)
207 		bzero((caddr_t)data, size);
208 
209 	if (fp->f_type == DTYPE_SOCKET)
210 		soioctl(fp->f_socket, com, data);
211 	else {
212 		register struct inode *ip = fp->f_inode;
213 		int fmt = ip->i_mode & IFMT;
214 		dev_t dev;
215 
216 		if (fmt != IFCHR) {
217 			if (com == FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
218 				*(off_t *)data = ip->i_size - fp->f_offset;
219 				goto returndata;
220 			}
221 			if (com != FIONBIO && com != FIOASYNC)
222 				u.u_error = ENOTTY;
223 			return;
224 		}
225 		dev = ip->i_rdev;
226 		u.u_r.r_val1 = 0;
227 		if ((u.u_procp->p_flag&SNUSIG) && setjmp(u.u_qsav)) {
228 			u.u_eosys = RESTARTSYS;
229 			return;
230 		}
231 		(*cdevsw[major(dev)].d_ioctl)(dev, com, data, 0);
232 	}
233 
234 returndata:
235 	/*
236 	 * Copy any data to user, size was
237 	 * already set and checked above.
238 	 */
239 	if (u.u_error == 0 && com&IOC_OUT)
240 		if (size && copyout(data, uap->cmarg, size))
241 			u.u_error = EFAULT;
242 }
243 
244 /*
245  * Do nothing specific version of line
246  * discipline specific ioctl command.
247  */
248 /*ARGSUSED*/
249 nullioctl(tp, cmd, data, flags)
250 	struct tty *tp;
251 	char *data;
252 	int flags;
253 {
254 
255 #ifdef lint
256 	tp = tp; data = data; flags = flags;
257 #endif
258 	return (cmd);
259 }
260 
261 /*
262  * Read the file corresponding to
263  * the inode pointed at by the argument.
264  * The actual read arguments are found
265  * in the variables:
266  *	u_base		core address for destination
267  *	u_offset	byte offset in file
268  *	u_count		number of bytes to read
269  *	u_segflg	read to kernel/user/user I
270  */
271 readi(ip)
272 	register struct inode *ip;
273 {
274 	struct buf *bp;
275 	struct fs *fs;
276 	dev_t dev;
277 	daddr_t lbn, bn;
278 	off_t diff;
279 	register int on, type;
280 	register unsigned n;
281 	int size;
282 	long bsize;
283 	extern int mem_no;
284 
285 	if (u.u_count == 0)
286 		return;
287 	dev = (dev_t)ip->i_rdev;
288 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
289 	    mem_no != major(dev))) {
290 		u.u_error = EINVAL;
291 		return;
292 	}
293 	ip->i_flag |= IACC;
294 	type = ip->i_mode&IFMT;
295 	if (type == IFCHR) {
296 		register c = u.u_count;
297 		struct uio auio;
298 		struct iovec aiov;
299 		auio.uio_iov = &aiov;
300 		auio.uio_iovcnt = 1;
301 		aiov.iov_base = u.u_base;
302 		aiov.iov_len = u.u_count;
303 		auio.uio_offset = u.u_offset;
304 		auio.uio_segflg = u.u_segflg;
305 		auio.uio_resid = u.u_count;
306 		(*cdevsw[major(dev)].d_read)(dev, &auio);
307 		CHARGE(sc_tio * (c - auio.uio_resid));
308 		u.u_count = auio.uio_resid;
309 		return;
310 	}
311 	if (type != IFBLK) {
312 		dev = ip->i_dev;
313 		fs = ip->i_fs;
314 		bsize = fs->fs_bsize;
315 	} else
316 		bsize = BLKDEV_IOSIZE;
317 	do {
318 		lbn = u.u_offset / bsize;
319 		on = u.u_offset % bsize;
320 		n = MIN((unsigned)(bsize - on), u.u_count);
321 		if (type != IFBLK) {
322 			diff = ip->i_size - u.u_offset;
323 			if (diff <= 0)
324 				return;
325 			if (diff < n)
326 				n = diff;
327 			bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
328 			if (u.u_error)
329 				return;
330 			size = blksize(fs, ip, lbn);
331 		} else {
332 			size = bsize;
333 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
334 			rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
335 			rasize = bsize;
336 		}
337 		if ((long)bn<0) {
338 			bp = geteblk(size);
339 			clrbuf(bp);
340 		} else if (ip->i_lastr + 1 == lbn)
341 			bp = breada(dev, bn, size, rablock, rasize);
342 		else
343 			bp = bread(dev, bn, size);
344 		ip->i_lastr = lbn;
345 		n = MIN(n, size - bp->b_resid);
346 		if (n != 0) {
347 			if (u.u_segflg != 1) {
348 				if (copyout(bp->b_un.b_addr+on, u.u_base, n)) {
349 					u.u_error = EFAULT;
350 					goto bad;
351 				}
352 			} else
353 				bcopy(bp->b_un.b_addr + on, u.u_base, n);
354 			u.u_base += n;
355 			u.u_offset += n;
356 			u.u_count -= n;
357 bad:
358 			;
359 		}
360 		if (n + on == bsize || u.u_offset == ip->i_size)
361 			bp->b_flags |= B_AGE;
362 		brelse(bp);
363 	} while (u.u_error == 0 && u.u_count != 0 && n != 0);
364 }
365 
366 /*
367  * Write the file corresponding to
368  * the inode pointed at by the argument.
369  * The actual write arguments are found
370  * in the variables:
371  *	u_base		core address for source
372  *	u_offset	byte offset in file
373  *	u_count		number of bytes to write
374  *	u_segflg	write to kernel/user/user I
375  */
376 writei(ip)
377 	register struct inode *ip;
378 {
379 	struct buf *bp;
380 	register struct fs *fs;
381 	dev_t dev;
382 	daddr_t lbn, bn;
383 	register int on, type;
384 	register unsigned n;
385 	long bsize;
386 	int size, i, count;
387 	extern int mem_no;
388 
389 	dev = (dev_t)ip->i_rdev;
390 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
391 	    mem_no != major(dev)) ) {
392 		u.u_error = EINVAL;
393 		return;
394 	}
395 	type = ip->i_mode & IFMT;
396 	if (type == IFCHR) {
397 		ip->i_flag |= IUPD|ICHG;
398 		CHARGE(sc_tio * u.u_count);
399 		(*cdevsw[major(dev)].d_write)(dev);
400 		return;
401 	}
402 	if (u.u_count == 0)
403 		return;
404 	if ((ip->i_mode & IFMT) == IFREG &&
405 	    u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
406 		psignal(u.u_procp, SIGXFSZ);
407 		u.u_error = EMFILE;
408 		return;
409 	}
410 	if (type!=IFBLK) {
411 		dev = ip->i_dev;
412 		fs = ip->i_fs;
413 		bsize = fs->fs_bsize;
414 	} else
415 		bsize = BLKDEV_IOSIZE;
416 	do {
417 		lbn = u.u_offset / bsize;
418 		on = u.u_offset % bsize;
419 		n = MIN((unsigned)(bsize - on), u.u_count);
420 		if (type != IFBLK) {
421 			bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
422 			if (u.u_error || (long)bn<0)
423 				return;
424 			if(u.u_offset + n > ip->i_size &&
425 			   (type == IFDIR || type == IFREG || type == IFLNK))
426 				ip->i_size = u.u_offset + n;
427 			size = blksize(fs, ip, lbn);
428 		} else {
429 			size = bsize;
430 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
431 		}
432 		count = howmany(size, DEV_BSIZE);
433 		for (i = 0; i < count; i += CLSIZE)
434 			if (mfind(dev, bn + i))
435 				munhash(dev, bn + i);
436 		if (n == bsize)
437 			bp = getblk(dev, bn, size);
438 		else
439 			bp = bread(dev, bn, size);
440 		if (u.u_segflg != 1) {
441 			if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
442 				u.u_error = EFAULT;
443 				goto bad;
444 			}
445 		} else
446 			bcopy(u.u_base, bp->b_un.b_addr + on, n);
447 		u.u_base += n;
448 		u.u_offset += n;
449 		u.u_count -= n;
450 bad:
451 		;
452 		if (u.u_error != 0)
453 			brelse(bp);
454 		else {
455 			if ((ip->i_mode&IFMT) == IFDIR)
456 				/*
457 				 * Writing to clear a directory entry.
458 				 * Must insure the write occurs before
459 				 * the inode is freed, or may end up
460 				 * pointing at a new (different) file
461 				 * if inode is quickly allocated again
462 				 * and system crashes.
463 				 */
464 				bwrite(bp);
465 			else if (n + on == bsize) {
466 				bp->b_flags |= B_AGE;
467 				bawrite(bp);
468 			} else
469 				bdwrite(bp);
470 		}
471 		ip->i_flag |= IUPD|ICHG;
472 		if (u.u_ruid != 0)
473 			ip->i_mode &= ~(ISUID|ISGID);
474 	} while (u.u_error == 0 && u.u_count != 0);
475 }
476 
477 /*
478  * Move n bytes at byte location
479  * &bp->b_un.b_addr[o] to/from (flag) the
480  * user/kernel (u.segflg) area starting at u.base.
481  * Update all the arguments by the number
482  * of bytes moved.
483  */
484 iomove(cp, n, flag)
485 	register caddr_t cp;
486 	register unsigned n;
487 {
488 	register int t;
489 
490 	if (n==0)
491 		return;
492 	if (u.u_segflg != 1) {
493 		if (flag==B_WRITE)
494 			t = copyin(u.u_base, (caddr_t)cp, n);
495 		else
496 			t = copyout((caddr_t)cp, u.u_base, n);
497 		if (t) {
498 			u.u_error = EFAULT;
499 			return;
500 		}
501 	} else
502 		if (flag == B_WRITE)
503 			bcopy(u.u_base, (caddr_t)cp, n);
504 		else
505 			bcopy((caddr_t)cp, u.u_base, n);
506 	u.u_base += n;
507 	u.u_offset += n;
508 	u.u_count -= n;
509 }
510 
511 readip(ip, uio)
512 	register struct inode *ip;
513 	register struct uio *uio;
514 {
515 	register struct iovec *iov;
516 	struct buf *bp;
517 	struct fs *fs;
518 	dev_t dev;
519 	daddr_t lbn, bn;
520 	off_t diff;
521 	register int on, type;
522 	register unsigned n;
523 	int size;
524 	long bsize;
525 	extern int mem_no;
526 	int error = 0;
527 
528 	dev = (dev_t)ip->i_rdev;
529 	if (uio->uio_offset < 0 &&
530 	    ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev)))
531 		return (EINVAL);
532 	ip->i_flag |= IACC;
533 	type = ip->i_mode&IFMT;
534 	if (type == IFCHR) {
535 		register c = u.u_count;
536 		(*cdevsw[major(dev)].d_read)(dev, uio);
537 		CHARGE(sc_tio * (c - uio->uio_resid));
538 		return (u.u_error);
539 	}
540 	if (type != IFBLK) {
541 		dev = ip->i_dev;
542 		fs = ip->i_fs;
543 		bsize = fs->fs_bsize;
544 	} else
545 		bsize = BLKDEV_IOSIZE;
546 nextiov:
547 	if (uio->uio_iovcnt == 0)
548 		return (0);
549 	iov = uio->uio_iov;
550 	if (iov->iov_len > 0)
551 	do {
552 		lbn = uio->uio_offset / bsize;
553 		on = uio->uio_offset % bsize;
554 		n = MIN((unsigned)(bsize - on), iov->iov_len);
555 		if (type != IFBLK) {
556 			diff = ip->i_size - uio->uio_offset;
557 			if (diff <= 0)
558 				return;
559 			if (diff < n)
560 				n = diff;
561 			bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
562 			if (u.u_error)
563 				return (u.u_error);
564 			size = blksize(fs, ip, lbn);
565 		} else {
566 			size = bsize;
567 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
568 			rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
569 			rasize = bsize;
570 		}
571 		if ((long)bn<0) {
572 			bp = geteblk(size);
573 			clrbuf(bp);
574 		} else if (ip->i_lastr + 1 == lbn)
575 			bp = breada(dev, bn, size, rablock, rasize);
576 		else
577 			bp = bread(dev, bn, size);
578 		ip->i_lastr = lbn;
579 		n = MIN(n, size - bp->b_resid);
580 		if (n != 0) {
581 			if (uio->uio_segflg != 1) {
582 				if (copyout(bp->b_un.b_addr+on, iov->iov_base, n)) {
583 					brelse(bp);
584 					return (EFAULT);
585 				}
586 			} else
587 				bcopy(bp->b_un.b_addr + on, iov->iov_base, n);
588 			iov->iov_base += n;
589 			uio->uio_offset += n;
590 			iov->iov_len -= n;
591 			uio->uio_resid -= n;
592 		}
593 		if (n + on == bsize || uio->uio_offset == ip->i_size)
594 			bp->b_flags |= B_AGE;
595 		brelse(bp);
596 	} while (u.u_error == 0 && iov->iov_len != 0 && n != 0);
597 	if (u.u_error == 0 && iov->iov_len == 0) {
598 		uio->uio_iov++;
599 		uio->uio_iovcnt--;
600 		goto nextiov;
601 	}
602 	return (error);
603 }
604 
605 uiomove(cp, n, dir, uio)
606 	register caddr_t cp;
607 	register unsigned n;
608 	enum uio_direction dir;
609 	struct uio *uio;
610 {
611 	register struct iovec *iov;
612 	int bad, cnt;
613 
614 	if (n == 0)
615 		return (0);
616 	if (uio->uio_segflg != 1) {
617 		if (dir == UIO_READFROM)
618 #ifdef notdef
619 			bad = copyuin(uio, (caddr_t)cp, n);
620 #else
621 			panic("uiomove");
622 #endif
623 		else
624 			bad = copyuout((caddr_t)cp, n, uio);
625 		if (bad)
626 			return (EFAULT);
627 	} else {
628 		while (n > 0 && uio->uio_iovcnt) {
629 			iov = uio->uio_iov;
630 			cnt = iov->iov_len;
631 			if (cnt > n)
632 				cnt = n;
633 			if (dir == UIO_READFROM)
634 				bcopy(iov->iov_base, (caddr_t)cp, cnt);
635 			else
636 				bcopy((caddr_t)cp, iov->iov_base, cnt);
637 			iov->iov_base += cnt;
638 			iov->iov_len -= cnt;
639 			uio->uio_resid -= cnt;
640 			n -= cnt;
641 		}
642 	}
643 	return (0);
644 }
645