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