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