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