xref: /csrg-svn/sys/kern/sys_generic.c (revision 7714)
1 /*	sys_generic.c	5.7	82/08/11	*/
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 		(*cdevsw[major(dev)].d_read)(dev);
291 		CHARGE(sc_tio * (c - u.u_count));
292 		return;
293 	}
294 	if (type != IFBLK) {
295 		dev = ip->i_dev;
296 		fs = ip->i_fs;
297 		bsize = fs->fs_bsize;
298 	} else
299 		bsize = BLKDEV_IOSIZE;
300 	do {
301 		lbn = u.u_offset / bsize;
302 		on = u.u_offset % bsize;
303 		n = MIN((unsigned)(bsize - on), u.u_count);
304 		if (type != IFBLK) {
305 			diff = ip->i_size - u.u_offset;
306 			if (diff <= 0)
307 				return;
308 			if (diff < n)
309 				n = diff;
310 			bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
311 			if (u.u_error)
312 				return;
313 			size = blksize(fs, ip, lbn);
314 		} else {
315 			size = bsize;
316 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
317 			rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
318 			rasize = bsize;
319 		}
320 		if ((long)bn<0) {
321 			bp = geteblk(size);
322 			clrbuf(bp);
323 		} else if (ip->i_lastr + 1 == lbn)
324 			bp = breada(dev, bn, size, rablock, rasize);
325 		else
326 			bp = bread(dev, bn, size);
327 		ip->i_lastr = lbn;
328 		n = MIN(n, size - bp->b_resid);
329 		if (n != 0) {
330 			if (u.u_segflg != 1) {
331 				if (copyout(bp->b_un.b_addr+on, u.u_base, n)) {
332 					u.u_error = EFAULT;
333 					goto bad;
334 				}
335 			} else
336 				bcopy(bp->b_un.b_addr + on, u.u_base, n);
337 			u.u_base += n;
338 			u.u_offset += n;
339 			u.u_count -= n;
340 bad:
341 			;
342 		}
343 		if (n + on == bsize || u.u_offset == ip->i_size)
344 			bp->b_flags |= B_AGE;
345 		brelse(bp);
346 	} while (u.u_error == 0 && u.u_count != 0 && n != 0);
347 }
348 
349 /*
350  * Write the file corresponding to
351  * the inode pointed at by the argument.
352  * The actual write arguments are found
353  * in the variables:
354  *	u_base		core address for source
355  *	u_offset	byte offset in file
356  *	u_count		number of bytes to write
357  *	u_segflg	write to kernel/user/user I
358  */
359 writei(ip)
360 	register struct inode *ip;
361 {
362 	struct buf *bp;
363 	register struct fs *fs;
364 	dev_t dev;
365 	daddr_t lbn, bn;
366 	register int on, type;
367 	register unsigned n;
368 	long bsize;
369 	int size, i, count;
370 	extern int mem_no;
371 
372 	dev = (dev_t)ip->i_rdev;
373 	if (u.u_offset < 0 && ((ip->i_mode&IFMT) != IFCHR ||
374 	    mem_no != major(dev)) ) {
375 		u.u_error = EINVAL;
376 		return;
377 	}
378 	type = ip->i_mode & IFMT;
379 	if (type == IFCHR) {
380 		ip->i_flag |= IUPD|ICHG;
381 		CHARGE(sc_tio * u.u_count);
382 		(*cdevsw[major(dev)].d_write)(dev);
383 		return;
384 	}
385 	if (u.u_count == 0)
386 		return;
387 	if ((ip->i_mode & IFMT) == IFREG &&
388 	    u.u_offset + u.u_count > u.u_limit[LIM_FSIZE]) {
389 		psignal(u.u_procp, SIGXFSZ);
390 		u.u_error = EMFILE;
391 		return;
392 	}
393 	if (type!=IFBLK) {
394 		dev = ip->i_dev;
395 		fs = ip->i_fs;
396 		bsize = fs->fs_bsize;
397 	} else
398 		bsize = BLKDEV_IOSIZE;
399 	do {
400 		lbn = u.u_offset / bsize;
401 		on = u.u_offset % bsize;
402 		n = MIN((unsigned)(bsize - on), u.u_count);
403 		if (type != IFBLK) {
404 			bn = fsbtodb(fs, bmap(ip, lbn, B_WRITE, (int)(on + n)));
405 			if (u.u_error || (long)bn<0)
406 				return;
407 			if(u.u_offset + n > ip->i_size &&
408 			   (type == IFDIR || type == IFREG || type == IFLNK))
409 				ip->i_size = u.u_offset + n;
410 			size = blksize(fs, ip, lbn);
411 		} else {
412 			size = bsize;
413 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
414 		}
415 		count = howmany(size, DEV_BSIZE);
416 		for (i = 0; i < count; i += CLSIZE)
417 			if (mfind(dev, bn + i))
418 				munhash(dev, bn + i);
419 		if (n == bsize)
420 			bp = getblk(dev, bn, size);
421 		else
422 			bp = bread(dev, bn, size);
423 		if (u.u_segflg != 1) {
424 			if (copyin(u.u_base, bp->b_un.b_addr + on, n)) {
425 				u.u_error = EFAULT;
426 				goto bad;
427 			}
428 		} else
429 			bcopy(u.u_base, bp->b_un.b_addr + on, n);
430 		u.u_base += n;
431 		u.u_offset += n;
432 		u.u_count -= n;
433 bad:
434 		;
435 		if (u.u_error != 0)
436 			brelse(bp);
437 		else {
438 			if ((ip->i_mode&IFMT) == IFDIR)
439 				/*
440 				 * Writing to clear a directory entry.
441 				 * Must insure the write occurs before
442 				 * the inode is freed, or may end up
443 				 * pointing at a new (different) file
444 				 * if inode is quickly allocated again
445 				 * and system crashes.
446 				 */
447 				bwrite(bp);
448 			else if (n + on == bsize) {
449 				bp->b_flags |= B_AGE;
450 				bawrite(bp);
451 			} else
452 				bdwrite(bp);
453 		}
454 		ip->i_flag |= IUPD|ICHG;
455 		if (u.u_ruid != 0)
456 			ip->i_mode &= ~(ISUID|ISGID);
457 	} while (u.u_error == 0 && u.u_count != 0);
458 }
459 
460 /*
461  * Move n bytes at byte location
462  * &bp->b_un.b_addr[o] to/from (flag) the
463  * user/kernel (u.segflg) area starting at u.base.
464  * Update all the arguments by the number
465  * of bytes moved.
466  */
467 iomove(cp, n, flag)
468 	register caddr_t cp;
469 	register unsigned n;
470 {
471 	register int t;
472 
473 	if (n==0)
474 		return;
475 	if (u.u_segflg != 1) {
476 		if (flag==B_WRITE)
477 			t = copyin(u.u_base, (caddr_t)cp, n);
478 		else
479 			t = copyout((caddr_t)cp, u.u_base, n);
480 		if (t) {
481 			u.u_error = EFAULT;
482 			return;
483 		}
484 	} else
485 		if (flag == B_WRITE)
486 			bcopy(u.u_base, (caddr_t)cp, n);
487 		else
488 			bcopy((caddr_t)cp, u.u_base, n);
489 	u.u_base += n;
490 	u.u_offset += n;
491 	u.u_count -= n;
492 }
493 
494 readip(ip, uio)
495 	register struct inode *ip;
496 	register struct uio *uio;
497 {
498 	register struct iovec *iov = uio->uio_iov;
499 	struct buf *bp;
500 	struct fs *fs;
501 	dev_t dev;
502 	daddr_t lbn, bn;
503 	off_t diff;
504 	register int on, type;
505 	register unsigned n;
506 	int size;
507 	long bsize;
508 	extern int mem_no;
509 	int error = 0;
510 
511 	uio->uio_resid = 0;
512 	if (uio->uio_iovcnt == 0)
513 		return (0);
514 	dev = (dev_t)ip->i_rdev;
515 	if (uio->uio_offset < 0 &&
516 	    ((ip->i_mode&IFMT) != IFCHR || mem_no != major(dev))) {
517 		error = EINVAL;
518 		goto bad;
519 	}
520 	ip->i_flag |= IACC;
521 	type = ip->i_mode&IFMT;
522 	if (type == IFCHR) {
523 		register c = u.u_count;
524 		error = (*cdevsw[major(dev)].d_read)(dev, uio);
525 		CHARGE(sc_tio * (c - u.u_count));
526 		return (error);
527 	}
528 	if (type != IFBLK) {
529 		dev = ip->i_dev;
530 		fs = ip->i_fs;
531 		bsize = fs->fs_bsize;
532 	} else
533 		bsize = BLKDEV_IOSIZE;
534 nextiov:
535 	if (uio->uio_iovcnt == 0)
536 		goto getresid;
537 	if (iov->iov_len > 0)
538 	do {
539 		lbn = uio->uio_offset / bsize;
540 		on = uio->uio_offset % bsize;
541 		n = MIN((unsigned)(bsize - on), iov->iov_len);
542 		if (type != IFBLK) {
543 			diff = ip->i_size - uio->uio_offset;
544 			if (diff <= 0)
545 				return;
546 			if (diff < n)
547 				n = diff;
548 			bn = fsbtodb(fs, bmap(ip, lbn, B_READ));
549 			if (u.u_error)
550 				goto getresid;
551 			size = blksize(fs, ip, lbn);
552 		} else {
553 			size = bsize;
554 			bn = lbn * (BLKDEV_IOSIZE/DEV_BSIZE);
555 			rablock = bn + (BLKDEV_IOSIZE/DEV_BSIZE);
556 			rasize = bsize;
557 		}
558 		if ((long)bn<0) {
559 			bp = geteblk(size);
560 			clrbuf(bp);
561 		} else if (ip->i_lastr + 1 == lbn)
562 			bp = breada(dev, bn, size, rablock, rasize);
563 		else
564 			bp = bread(dev, bn, size);
565 		ip->i_lastr = lbn;
566 		n = MIN(n, size - bp->b_resid);
567 		if (n != 0) {
568 			if (uio->uio_segflg != 1) {
569 				if (copyout(bp->b_un.b_addr+on, iov->iov_base, n)) {
570 					error = EFAULT;
571 					goto getresid;
572 				}
573 			} else
574 				bcopy(bp->b_un.b_addr + on, iov->iov_base, n);
575 			iov->iov_base += n;
576 			uio->uio_offset += n;
577 			iov->iov_len -= n;
578 bad:
579 			;
580 		}
581 		if (n + on == bsize || uio->uio_offset == ip->i_size)
582 			bp->b_flags |= B_AGE;
583 		brelse(bp);
584 	} while (u.u_error == 0 && iov->iov_len != 0 && n != 0);
585 	if (u.u_error == 0 && n > 0) {
586 		iov++;
587 		uio->uio_iovcnt--;
588 		goto nextiov;
589 	}
590 getresid:
591 	while (uio->uio_iovcnt > 0) {
592 		uio->uio_resid += iov->iov_len;
593 		iov++;
594 		uio->uio_iovcnt--;
595 	}
596 	return (error);
597 }
598