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