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