xref: /original-bsd/sys/kern/sys_generic.c (revision 333da485)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * %sccs.include.redist.c%
11  *
12  *	@(#)sys_generic.c	8.5 (Berkeley) 01/21/94
13  */
14 
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/filedesc.h>
18 #include <sys/ioctl.h>
19 #include <sys/file.h>
20 #include <sys/proc.h>
21 #include <sys/socketvar.h>
22 #include <sys/uio.h>
23 #include <sys/kernel.h>
24 #include <sys/stat.h>
25 #include <sys/malloc.h>
26 #ifdef KTRACE
27 #include <sys/ktrace.h>
28 #endif
29 
30 /*
31  * Read system call.
32  */
33 struct read_args {
34 	int	fd;
35 	char	*buf;
36 	u_int	nbyte;
37 };
38 /* ARGSUSED */
39 read(p, uap, retval)
40 	struct proc *p;
41 	register struct read_args *uap;
42 	int *retval;
43 {
44 	register struct file *fp;
45 	register struct filedesc *fdp = p->p_fd;
46 	struct uio auio;
47 	struct iovec aiov;
48 	long cnt, error = 0;
49 #ifdef KTRACE
50 	struct iovec ktriov;
51 #endif
52 
53 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
54 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
55 	    (fp->f_flag & FREAD) == 0)
56 		return (EBADF);
57 	aiov.iov_base = (caddr_t)uap->buf;
58 	aiov.iov_len = uap->nbyte;
59 	auio.uio_iov = &aiov;
60 	auio.uio_iovcnt = 1;
61 	auio.uio_resid = uap->nbyte;
62 	auio.uio_rw = UIO_READ;
63 	auio.uio_segflg = UIO_USERSPACE;
64 	auio.uio_procp = p;
65 #ifdef KTRACE
66 	/*
67 	 * if tracing, save a copy of iovec
68 	 */
69 	if (KTRPOINT(p, KTR_GENIO))
70 		ktriov = aiov;
71 #endif
72 	cnt = uap->nbyte;
73 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
74 		if (auio.uio_resid != cnt && (error == ERESTART ||
75 		    error == EINTR || error == EWOULDBLOCK))
76 			error = 0;
77 	cnt -= auio.uio_resid;
78 #ifdef KTRACE
79 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
80 		ktrgenio(p->p_tracep, uap->fd, UIO_READ, &ktriov, cnt, error);
81 #endif
82 	*retval = cnt;
83 	return (error);
84 }
85 
86 /*
87  * Scatter read system call.
88  */
89 struct readv_args {
90 	int	fdes;
91 	struct	iovec *iovp;
92 	u_int	iovcnt;
93 };
94 readv(p, uap, retval)
95 	struct proc *p;
96 	register struct readv_args *uap;
97 	int *retval;
98 {
99 	register struct file *fp;
100 	register struct filedesc *fdp = p->p_fd;
101 	struct uio auio;
102 	register struct iovec *iov;
103 	struct iovec *needfree;
104 	struct iovec aiov[UIO_SMALLIOV];
105 	long i, cnt, error = 0;
106 	u_int iovlen;
107 #ifdef KTRACE
108 	struct iovec *ktriov = NULL;
109 #endif
110 
111 	if (((u_int)uap->fdes) >= fdp->fd_nfiles ||
112 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
113 	    (fp->f_flag & FREAD) == 0)
114 		return (EBADF);
115 	/* note: can't use iovlen until iovcnt is validated */
116 	iovlen = uap->iovcnt * sizeof (struct iovec);
117 	if (uap->iovcnt > UIO_SMALLIOV) {
118 		if (uap->iovcnt > UIO_MAXIOV)
119 			return (EINVAL);
120 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
121 		needfree = iov;
122 	} else {
123 		iov = aiov;
124 		needfree = NULL;
125 	}
126 	auio.uio_iov = iov;
127 	auio.uio_iovcnt = uap->iovcnt;
128 	auio.uio_rw = UIO_READ;
129 	auio.uio_segflg = UIO_USERSPACE;
130 	auio.uio_procp = p;
131 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
132 		goto done;
133 	auio.uio_resid = 0;
134 	for (i = 0; i < uap->iovcnt; i++) {
135 		if (iov->iov_len < 0) {
136 			error = EINVAL;
137 			goto done;
138 		}
139 		auio.uio_resid += iov->iov_len;
140 		if (auio.uio_resid < 0) {
141 			error = EINVAL;
142 			goto done;
143 		}
144 		iov++;
145 	}
146 #ifdef KTRACE
147 	/*
148 	 * if tracing, save a copy of iovec
149 	 */
150 	if (KTRPOINT(p, KTR_GENIO))  {
151 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
152 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
153 	}
154 #endif
155 	cnt = auio.uio_resid;
156 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
157 		if (auio.uio_resid != cnt && (error == ERESTART ||
158 		    error == EINTR || error == EWOULDBLOCK))
159 			error = 0;
160 	cnt -= auio.uio_resid;
161 #ifdef KTRACE
162 	if (ktriov != NULL) {
163 		if (error == 0)
164 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
165 			    cnt, error);
166 		FREE(ktriov, M_TEMP);
167 	}
168 #endif
169 	*retval = cnt;
170 done:
171 	if (needfree)
172 		FREE(needfree, M_IOV);
173 	return (error);
174 }
175 
176 /*
177  * Write system call
178  */
179 struct write_args {
180 	int	fd;
181 	char	*buf;
182 	u_int	nbyte;
183 };
184 write(p, uap, retval)
185 	struct proc *p;
186 	register struct write_args *uap;
187 	int *retval;
188 {
189 	register struct file *fp;
190 	register struct filedesc *fdp = p->p_fd;
191 	struct uio auio;
192 	struct iovec aiov;
193 	long cnt, error = 0;
194 #ifdef KTRACE
195 	struct iovec ktriov;
196 #endif
197 
198 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
199 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
200 	    (fp->f_flag & FWRITE) == 0)
201 		return (EBADF);
202 	aiov.iov_base = (caddr_t)uap->buf;
203 	aiov.iov_len = uap->nbyte;
204 	auio.uio_iov = &aiov;
205 	auio.uio_iovcnt = 1;
206 	auio.uio_resid = uap->nbyte;
207 	auio.uio_rw = UIO_WRITE;
208 	auio.uio_segflg = UIO_USERSPACE;
209 	auio.uio_procp = p;
210 #ifdef KTRACE
211 	/*
212 	 * if tracing, save a copy of iovec
213 	 */
214 	if (KTRPOINT(p, KTR_GENIO))
215 		ktriov = aiov;
216 #endif
217 	cnt = uap->nbyte;
218 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
219 		if (auio.uio_resid != cnt && (error == ERESTART ||
220 		    error == EINTR || error == EWOULDBLOCK))
221 			error = 0;
222 		if (error == EPIPE)
223 			psignal(p, SIGPIPE);
224 	}
225 	cnt -= auio.uio_resid;
226 #ifdef KTRACE
227 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
228 		ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
229 		    &ktriov, cnt, error);
230 #endif
231 	*retval = cnt;
232 	return (error);
233 }
234 
235 /*
236  * Gather write system call
237  */
238 struct writev_args {
239 	int	fd;
240 	struct	iovec *iovp;
241 	u_int	iovcnt;
242 };
243 writev(p, uap, retval)
244 	struct proc *p;
245 	register struct writev_args *uap;
246 	int *retval;
247 {
248 	register struct file *fp;
249 	register struct filedesc *fdp = p->p_fd;
250 	struct uio auio;
251 	register struct iovec *iov;
252 	struct iovec *needfree;
253 	struct iovec aiov[UIO_SMALLIOV];
254 	long i, cnt, error = 0;
255 	u_int iovlen;
256 #ifdef KTRACE
257 	struct iovec *ktriov = NULL;
258 #endif
259 
260 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
261 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
262 	    (fp->f_flag & FWRITE) == 0)
263 		return (EBADF);
264 	/* note: can't use iovlen until iovcnt is validated */
265 	iovlen = uap->iovcnt * sizeof (struct iovec);
266 	if (uap->iovcnt > UIO_SMALLIOV) {
267 		if (uap->iovcnt > UIO_MAXIOV)
268 			return (EINVAL);
269 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
270 		needfree = iov;
271 	} else {
272 		iov = aiov;
273 		needfree = NULL;
274 	}
275 	auio.uio_iov = iov;
276 	auio.uio_iovcnt = uap->iovcnt;
277 	auio.uio_rw = UIO_WRITE;
278 	auio.uio_segflg = UIO_USERSPACE;
279 	auio.uio_procp = p;
280 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
281 		goto done;
282 	auio.uio_resid = 0;
283 	for (i = 0; i < uap->iovcnt; i++) {
284 		if (iov->iov_len < 0) {
285 			error = EINVAL;
286 			goto done;
287 		}
288 		auio.uio_resid += iov->iov_len;
289 		if (auio.uio_resid < 0) {
290 			error = EINVAL;
291 			goto done;
292 		}
293 		iov++;
294 	}
295 #ifdef KTRACE
296 	/*
297 	 * if tracing, save a copy of iovec
298 	 */
299 	if (KTRPOINT(p, KTR_GENIO))  {
300 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
301 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
302 	}
303 #endif
304 	cnt = auio.uio_resid;
305 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
306 		if (auio.uio_resid != cnt && (error == ERESTART ||
307 		    error == EINTR || error == EWOULDBLOCK))
308 			error = 0;
309 		if (error == EPIPE)
310 			psignal(p, SIGPIPE);
311 	}
312 	cnt -= auio.uio_resid;
313 #ifdef KTRACE
314 	if (ktriov != NULL) {
315 		if (error == 0)
316 			ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
317 				ktriov, cnt, error);
318 		FREE(ktriov, M_TEMP);
319 	}
320 #endif
321 	*retval = cnt;
322 done:
323 	if (needfree)
324 		FREE(needfree, M_IOV);
325 	return (error);
326 }
327 
328 /*
329  * Ioctl system call
330  */
331 struct ioctl_args {
332 	int	fd;
333 	int	com;
334 	caddr_t	data;
335 };
336 /* ARGSUSED */
337 ioctl(p, uap, retval)
338 	struct proc *p;
339 	register struct ioctl_args *uap;
340 	int *retval;
341 {
342 	register struct file *fp;
343 	register struct filedesc *fdp;
344 	register int com, error;
345 	register u_int size;
346 	caddr_t data, memp;
347 	int tmp;
348 #define STK_PARAMS	128
349 	char stkbuf[STK_PARAMS];
350 
351 	fdp = p->p_fd;
352 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
353 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
354 		return (EBADF);
355 
356 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
357 		return (EBADF);
358 
359 	switch (com = uap->com) {
360 	case FIONCLEX:
361 		fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE;
362 		return (0);
363 	case FIOCLEX:
364 		fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE;
365 		return (0);
366 	}
367 
368 	/*
369 	 * Interpret high order word to find amount of data to be
370 	 * copied to/from the user's address space.
371 	 */
372 	size = IOCPARM_LEN(com);
373 	if (size > IOCPARM_MAX)
374 		return (ENOTTY);
375 	memp = NULL;
376 	if (size > sizeof (stkbuf)) {
377 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
378 		data = memp;
379 	} else
380 		data = stkbuf;
381 	if (com&IOC_IN) {
382 		if (size) {
383 			error = copyin(uap->data, data, (u_int)size);
384 			if (error) {
385 				if (memp)
386 					free(memp, M_IOCTLOPS);
387 				return (error);
388 			}
389 		} else
390 			*(caddr_t *)data = uap->data;
391 	} else if ((com&IOC_OUT) && size)
392 		/*
393 		 * Zero the buffer so the user always
394 		 * gets back something deterministic.
395 		 */
396 		bzero(data, size);
397 	else if (com&IOC_VOID)
398 		*(caddr_t *)data = uap->data;
399 
400 	switch (com) {
401 
402 	case FIONBIO:
403 		if (tmp = *(int *)data)
404 			fp->f_flag |= FNONBLOCK;
405 		else
406 			fp->f_flag &= ~FNONBLOCK;
407 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
408 		break;
409 
410 	case FIOASYNC:
411 		if (tmp = *(int *)data)
412 			fp->f_flag |= FASYNC;
413 		else
414 			fp->f_flag &= ~FASYNC;
415 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
416 		break;
417 
418 	case FIOSETOWN:
419 		tmp = *(int *)data;
420 		if (fp->f_type == DTYPE_SOCKET) {
421 			((struct socket *)fp->f_data)->so_pgid = tmp;
422 			error = 0;
423 			break;
424 		}
425 		if (tmp <= 0) {
426 			tmp = -tmp;
427 		} else {
428 			struct proc *p1 = pfind(tmp);
429 			if (p1 == 0) {
430 				error = ESRCH;
431 				break;
432 			}
433 			tmp = p1->p_pgrp->pg_id;
434 		}
435 		error = (*fp->f_ops->fo_ioctl)
436 			(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
437 		break;
438 
439 	case FIOGETOWN:
440 		if (fp->f_type == DTYPE_SOCKET) {
441 			error = 0;
442 			*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
443 			break;
444 		}
445 		error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
446 		*(int *)data = -*(int *)data;
447 		break;
448 
449 	default:
450 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
451 		/*
452 		 * Copy any data to user, size was
453 		 * already set and checked above.
454 		 */
455 		if (error == 0 && (com&IOC_OUT) && size)
456 			error = copyout(data, uap->data, (u_int)size);
457 		break;
458 	}
459 	if (memp)
460 		free(memp, M_IOCTLOPS);
461 	return (error);
462 }
463 
464 int	selwait, nselcoll;
465 
466 /*
467  * Select system call.
468  */
469 struct select_args {
470 	u_int	nd;
471 	fd_set	*in, *ou, *ex;
472 	struct	timeval *tv;
473 };
474 select(p, uap, retval)
475 	register struct proc *p;
476 	register struct select_args *uap;
477 	int *retval;
478 {
479 	fd_set ibits[3], obits[3];
480 	struct timeval atv;
481 	int s, ncoll, error = 0, timo;
482 	u_int ni;
483 
484 	bzero((caddr_t)ibits, sizeof(ibits));
485 	bzero((caddr_t)obits, sizeof(obits));
486 	if (uap->nd > FD_SETSIZE)
487 		return (EINVAL);
488 	if (uap->nd > p->p_fd->fd_nfiles)
489 		uap->nd = p->p_fd->fd_nfiles;	/* forgiving; slightly wrong */
490 	ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask);
491 
492 #define	getbits(name, x) \
493 	if (uap->name && \
494 	    (error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], ni))) \
495 		goto done;
496 	getbits(in, 0);
497 	getbits(ou, 1);
498 	getbits(ex, 2);
499 #undef	getbits
500 
501 	if (uap->tv) {
502 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
503 			sizeof (atv));
504 		if (error)
505 			goto done;
506 		if (itimerfix(&atv)) {
507 			error = EINVAL;
508 			goto done;
509 		}
510 		s = splclock();
511 		timevaladd(&atv, (struct timeval *)&time);
512 		timo = hzto(&atv);
513 		/*
514 		 * Avoid inadvertently sleeping forever.
515 		 */
516 		if (timo == 0)
517 			timo = 1;
518 		splx(s);
519 	} else
520 		timo = 0;
521 retry:
522 	ncoll = nselcoll;
523 	p->p_flag |= P_SELECT;
524 	error = selscan(p, ibits, obits, uap->nd, retval);
525 	if (error || *retval)
526 		goto done;
527 	s = splhigh();
528 	/* this should be timercmp(&time, &atv, >=) */
529 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
530 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
531 		splx(s);
532 		goto done;
533 	}
534 	if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
535 		splx(s);
536 		goto retry;
537 	}
538 	p->p_flag &= ~P_SELECT;
539 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
540 	splx(s);
541 	if (error == 0)
542 		goto retry;
543 done:
544 	p->p_flag &= ~P_SELECT;
545 	/* select is not restarted after signals... */
546 	if (error == ERESTART)
547 		error = EINTR;
548 	if (error == EWOULDBLOCK)
549 		error = 0;
550 #define	putbits(name, x) \
551 	if (uap->name && \
552 	    (error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, ni))) \
553 		error = error2;
554 	if (error == 0) {
555 		int error2;
556 
557 		putbits(in, 0);
558 		putbits(ou, 1);
559 		putbits(ex, 2);
560 #undef putbits
561 	}
562 	return (error);
563 }
564 
565 selscan(p, ibits, obits, nfd, retval)
566 	struct proc *p;
567 	fd_set *ibits, *obits;
568 	int nfd, *retval;
569 {
570 	register struct filedesc *fdp = p->p_fd;
571 	register int msk, i, j, fd;
572 	register fd_mask bits;
573 	struct file *fp;
574 	int n = 0;
575 	static int flag[3] = { FREAD, FWRITE, 0 };
576 
577 	for (msk = 0; msk < 3; msk++) {
578 		for (i = 0; i < nfd; i += NFDBITS) {
579 			bits = ibits[msk].fds_bits[i/NFDBITS];
580 			while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
581 				bits &= ~(1 << j);
582 				fp = fdp->fd_ofiles[fd];
583 				if (fp == NULL)
584 					return (EBADF);
585 				if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
586 					FD_SET(fd, &obits[msk]);
587 					n++;
588 				}
589 			}
590 		}
591 	}
592 	*retval = n;
593 	return (0);
594 }
595 
596 /*ARGSUSED*/
597 seltrue(dev, flag, p)
598 	dev_t dev;
599 	int flag;
600 	struct proc *p;
601 {
602 
603 	return (1);
604 }
605 
606 /*
607  * Record a select request.
608  */
609 void
610 selrecord(selector, sip)
611 	struct proc *selector;
612 	struct selinfo *sip;
613 {
614 	struct proc *p;
615 	pid_t mypid;
616 
617 	mypid = selector->p_pid;
618 	if (sip->si_pid == mypid)
619 		return;
620 	if (sip->si_pid && (p = pfind(sip->si_pid)) &&
621 	    p->p_wchan == (caddr_t)&selwait)
622 		sip->si_flags |= SI_COLL;
623 	else
624 		sip->si_pid = mypid;
625 }
626 
627 /*
628  * Do a wakeup when a selectable event occurs.
629  */
630 void
631 selwakeup(sip)
632 	register struct selinfo *sip;
633 {
634 	register struct proc *p;
635 	int s;
636 
637 	if (sip->si_pid == 0)
638 		return;
639 	if (sip->si_flags & SI_COLL) {
640 		nselcoll++;
641 		sip->si_flags &= ~SI_COLL;
642 		wakeup((caddr_t)&selwait);
643 	}
644 	p = pfind(sip->si_pid);
645 	sip->si_pid = 0;
646 	if (p != NULL) {
647 		s = splhigh();
648 		if (p->p_wchan == (caddr_t)&selwait) {
649 			if (p->p_stat == SSLEEP)
650 				setrunnable(p);
651 			else
652 				unsleep(p);
653 		} else if (p->p_flag & P_SELECT)
654 			p->p_flag &= ~P_SELECT;
655 		splx(s);
656 	}
657 }
658