xref: /csrg-svn/sys/kern/sys_generic.c (revision 65771)
123384Smckusick /*
263865Sbostic  * Copyright (c) 1982, 1986, 1989, 1993
363865Sbostic  *	The Regents of the University of California.  All rights reserved.
4*65771Sbostic  * (c) UNIX System Laboratories, Inc.
5*65771Sbostic  * All or some portions of this file are derived from material licensed
6*65771Sbostic  * to the University of California by American Telephone and Telegraph
7*65771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8*65771Sbostic  * the permission of UNIX System Laboratories, Inc.
923384Smckusick  *
1044444Sbostic  * %sccs.include.redist.c%
1137728Smckusick  *
12*65771Sbostic  *	@(#)sys_generic.c	8.5 (Berkeley) 01/21/94
1323384Smckusick  */
147423Sroot 
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/filedesc.h>
1856517Sbostic #include <sys/ioctl.h>
1956517Sbostic #include <sys/file.h>
2056517Sbostic #include <sys/proc.h>
2156517Sbostic #include <sys/socketvar.h>
2256517Sbostic #include <sys/uio.h>
2356517Sbostic #include <sys/kernel.h>
2456517Sbostic #include <sys/stat.h>
2556517Sbostic #include <sys/malloc.h>
2637127Skarels #ifdef KTRACE
2756517Sbostic #include <sys/ktrace.h>
2837127Skarels #endif
297423Sroot 
307423Sroot /*
317423Sroot  * Read system call.
327423Sroot  */
3354930Storek struct read_args {
3464409Sbostic 	int	fd;
3564409Sbostic 	char	*buf;
3664409Sbostic 	u_int	nbyte;
3754930Storek };
3845122Sbostic /* ARGSUSED */
3942922Smckusick read(p, uap, retval)
4042922Smckusick 	struct proc *p;
4154930Storek 	register struct read_args *uap;
4242922Smckusick 	int *retval;
4342922Smckusick {
4437728Smckusick 	register struct file *fp;
4545914Smckusick 	register struct filedesc *fdp = p->p_fd;
467746Sroot 	struct uio auio;
477746Sroot 	struct iovec aiov;
4837728Smckusick 	long cnt, error = 0;
4937728Smckusick #ifdef KTRACE
5037728Smckusick 	struct iovec ktriov;
5137728Smckusick #endif
527423Sroot 
5364409Sbostic 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
5464409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
5537728Smckusick 	    (fp->f_flag & FREAD) == 0)
5644405Skarels 		return (EBADF);
5764409Sbostic 	aiov.iov_base = (caddr_t)uap->buf;
5864409Sbostic 	aiov.iov_len = uap->nbyte;
597820Sroot 	auio.uio_iov = &aiov;
607820Sroot 	auio.uio_iovcnt = 1;
6164409Sbostic 	auio.uio_resid = uap->nbyte;
6237728Smckusick 	auio.uio_rw = UIO_READ;
6337728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
6448027Smckusick 	auio.uio_procp = p;
6537728Smckusick #ifdef KTRACE
6637728Smckusick 	/*
6737728Smckusick 	 * if tracing, save a copy of iovec
6837728Smckusick 	 */
6942922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
7037728Smckusick 		ktriov = aiov;
7137728Smckusick #endif
7264409Sbostic 	cnt = uap->nbyte;
7340703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
7440703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
7540703Skarels 		    error == EINTR || error == EWOULDBLOCK))
7640703Skarels 			error = 0;
7737728Smckusick 	cnt -= auio.uio_resid;
7837728Smckusick #ifdef KTRACE
7942922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
8064409Sbostic 		ktrgenio(p->p_tracep, uap->fd, UIO_READ, &ktriov, cnt, error);
8137728Smckusick #endif
8242922Smckusick 	*retval = cnt;
8344405Skarels 	return (error);
847820Sroot }
857820Sroot 
8642922Smckusick /*
8742922Smckusick  * Scatter read system call.
8842922Smckusick  */
8954930Storek struct readv_args {
9054930Storek 	int	fdes;
9154930Storek 	struct	iovec *iovp;
9264409Sbostic 	u_int	iovcnt;
9354930Storek };
9442922Smckusick readv(p, uap, retval)
9542922Smckusick 	struct proc *p;
9654930Storek 	register struct readv_args *uap;
9742922Smckusick 	int *retval;
9842922Smckusick {
9937728Smckusick 	register struct file *fp;
10045914Smckusick 	register struct filedesc *fdp = p->p_fd;
1017820Sroot 	struct uio auio;
10237728Smckusick 	register struct iovec *iov;
10352481Storek 	struct iovec *needfree;
10437728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
10537728Smckusick 	long i, cnt, error = 0;
10664409Sbostic 	u_int iovlen;
10737728Smckusick #ifdef KTRACE
10837728Smckusick 	struct iovec *ktriov = NULL;
10937728Smckusick #endif
1107820Sroot 
11164409Sbostic 	if (((u_int)uap->fdes) >= fdp->fd_nfiles ||
11247974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
11337728Smckusick 	    (fp->f_flag & FREAD) == 0)
11444405Skarels 		return (EBADF);
11544939Skarels 	/* note: can't use iovlen until iovcnt is validated */
11644939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
11737127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
11837728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
11944405Skarels 			return (EINVAL);
12044939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
12152481Storek 		needfree = iov;
12252481Storek 	} else {
12337127Skarels 		iov = aiov;
12452481Storek 		needfree = NULL;
12552481Storek 	}
12637127Skarels 	auio.uio_iov = iov;
1277820Sroot 	auio.uio_iovcnt = uap->iovcnt;
12837728Smckusick 	auio.uio_rw = UIO_READ;
12937728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
13048027Smckusick 	auio.uio_procp = p;
13144939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
13237127Skarels 		goto done;
13337728Smckusick 	auio.uio_resid = 0;
13437728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
13537728Smckusick 		if (iov->iov_len < 0) {
13637728Smckusick 			error = EINVAL;
13737728Smckusick 			goto done;
13837728Smckusick 		}
13937728Smckusick 		auio.uio_resid += iov->iov_len;
14037728Smckusick 		if (auio.uio_resid < 0) {
14137728Smckusick 			error = EINVAL;
14237728Smckusick 			goto done;
14337728Smckusick 		}
14437728Smckusick 		iov++;
14537728Smckusick 	}
14637728Smckusick #ifdef KTRACE
14737728Smckusick 	/*
14837728Smckusick 	 * if tracing, save a copy of iovec
14937728Smckusick 	 */
15042922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
15137728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
15237728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
15337728Smckusick 	}
15437728Smckusick #endif
15537728Smckusick 	cnt = auio.uio_resid;
15640703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
15740703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
15840703Skarels 		    error == EINTR || error == EWOULDBLOCK))
15940703Skarels 			error = 0;
16037728Smckusick 	cnt -= auio.uio_resid;
16137728Smckusick #ifdef KTRACE
16237728Smckusick 	if (ktriov != NULL) {
16341178Smarc 		if (error == 0)
16443448Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
16543448Smckusick 			    cnt, error);
16637728Smckusick 		FREE(ktriov, M_TEMP);
16737728Smckusick 	}
16837728Smckusick #endif
16942922Smckusick 	*retval = cnt;
17037127Skarels done:
17152481Storek 	if (needfree)
17252481Storek 		FREE(needfree, M_IOV);
17344405Skarels 	return (error);
1747423Sroot }
1757423Sroot 
1767423Sroot /*
1777423Sroot  * Write system call
1787423Sroot  */
17954930Storek struct write_args {
18064409Sbostic 	int	fd;
18164409Sbostic 	char	*buf;
18264409Sbostic 	u_int	nbyte;
18354930Storek };
18442922Smckusick write(p, uap, retval)
18542922Smckusick 	struct proc *p;
18654930Storek 	register struct write_args *uap;
18742922Smckusick 	int *retval;
18842922Smckusick {
18937728Smckusick 	register struct file *fp;
19045914Smckusick 	register struct filedesc *fdp = p->p_fd;
1917820Sroot 	struct uio auio;
1927820Sroot 	struct iovec aiov;
19337728Smckusick 	long cnt, error = 0;
19437728Smckusick #ifdef KTRACE
19537728Smckusick 	struct iovec ktriov;
19637728Smckusick #endif
1977423Sroot 
19864409Sbostic 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
19964409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
20037728Smckusick 	    (fp->f_flag & FWRITE) == 0)
20144405Skarels 		return (EBADF);
20264409Sbostic 	aiov.iov_base = (caddr_t)uap->buf;
20364409Sbostic 	aiov.iov_len = uap->nbyte;
2047820Sroot 	auio.uio_iov = &aiov;
2057820Sroot 	auio.uio_iovcnt = 1;
20664409Sbostic 	auio.uio_resid = uap->nbyte;
20737728Smckusick 	auio.uio_rw = UIO_WRITE;
20837728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
20948027Smckusick 	auio.uio_procp = p;
21037728Smckusick #ifdef KTRACE
21137728Smckusick 	/*
21237728Smckusick 	 * if tracing, save a copy of iovec
21337728Smckusick 	 */
21442922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
21537728Smckusick 		ktriov = aiov;
21637728Smckusick #endif
21764409Sbostic 	cnt = uap->nbyte;
21840703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
21940703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
22040703Skarels 		    error == EINTR || error == EWOULDBLOCK))
22140703Skarels 			error = 0;
22240703Skarels 		if (error == EPIPE)
22342922Smckusick 			psignal(p, SIGPIPE);
22440703Skarels 	}
22537728Smckusick 	cnt -= auio.uio_resid;
22637728Smckusick #ifdef KTRACE
22742922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
22864409Sbostic 		ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
22943448Smckusick 		    &ktriov, cnt, error);
23037728Smckusick #endif
23142922Smckusick 	*retval = cnt;
23244405Skarels 	return (error);
2337820Sroot }
2347820Sroot 
23542922Smckusick /*
23642922Smckusick  * Gather write system call
23742922Smckusick  */
23854930Storek struct writev_args {
23964409Sbostic 	int	fd;
24054930Storek 	struct	iovec *iovp;
24164409Sbostic 	u_int	iovcnt;
24254930Storek };
24342922Smckusick writev(p, uap, retval)
24442922Smckusick 	struct proc *p;
24554930Storek 	register struct writev_args *uap;
24642922Smckusick 	int *retval;
24742922Smckusick {
24837728Smckusick 	register struct file *fp;
24945914Smckusick 	register struct filedesc *fdp = p->p_fd;
2507820Sroot 	struct uio auio;
25137728Smckusick 	register struct iovec *iov;
25252481Storek 	struct iovec *needfree;
25337728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
25437728Smckusick 	long i, cnt, error = 0;
25564409Sbostic 	u_int iovlen;
25637728Smckusick #ifdef KTRACE
25737728Smckusick 	struct iovec *ktriov = NULL;
25837728Smckusick #endif
2597820Sroot 
26064409Sbostic 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
26164409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
26237728Smckusick 	    (fp->f_flag & FWRITE) == 0)
26344405Skarels 		return (EBADF);
26444939Skarels 	/* note: can't use iovlen until iovcnt is validated */
26544939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
26637127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
26737728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
26844405Skarels 			return (EINVAL);
26944939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
27052481Storek 		needfree = iov;
27152481Storek 	} else {
27237127Skarels 		iov = aiov;
27352481Storek 		needfree = NULL;
27452481Storek 	}
27537127Skarels 	auio.uio_iov = iov;
2767820Sroot 	auio.uio_iovcnt = uap->iovcnt;
27737728Smckusick 	auio.uio_rw = UIO_WRITE;
27837728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
27948027Smckusick 	auio.uio_procp = p;
28044939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
28137127Skarels 		goto done;
28237728Smckusick 	auio.uio_resid = 0;
28337728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
2847820Sroot 		if (iov->iov_len < 0) {
28537728Smckusick 			error = EINVAL;
28637728Smckusick 			goto done;
2877820Sroot 		}
28837728Smckusick 		auio.uio_resid += iov->iov_len;
28937728Smckusick 		if (auio.uio_resid < 0) {
29037728Smckusick 			error = EINVAL;
29137728Smckusick 			goto done;
2927820Sroot 		}
29313270Ssam 		iov++;
2947820Sroot 	}
29537127Skarels #ifdef KTRACE
29637728Smckusick 	/*
29737728Smckusick 	 * if tracing, save a copy of iovec
29837728Smckusick 	 */
29942922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
30037127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
30137728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
30237127Skarels 	}
30337127Skarels #endif
30437728Smckusick 	cnt = auio.uio_resid;
30540703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
30640703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
30740703Skarels 		    error == EINTR || error == EWOULDBLOCK))
30840703Skarels 			error = 0;
30940703Skarels 		if (error == EPIPE)
31042922Smckusick 			psignal(p, SIGPIPE);
31140703Skarels 	}
31237728Smckusick 	cnt -= auio.uio_resid;
31337127Skarels #ifdef KTRACE
31437127Skarels 	if (ktriov != NULL) {
31541178Smarc 		if (error == 0)
31664409Sbostic 			ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
31743448Smckusick 				ktriov, cnt, error);
31837127Skarels 		FREE(ktriov, M_TEMP);
31937127Skarels 	}
32037127Skarels #endif
32142922Smckusick 	*retval = cnt;
32237728Smckusick done:
32352481Storek 	if (needfree)
32452481Storek 		FREE(needfree, M_IOV);
32544405Skarels 	return (error);
3267423Sroot }
3277423Sroot 
3287423Sroot /*
3297423Sroot  * Ioctl system call
3307423Sroot  */
33154930Storek struct ioctl_args {
33264409Sbostic 	int	fd;
33364409Sbostic 	int	com;
33464409Sbostic 	caddr_t	data;
33554930Storek };
33642922Smckusick /* ARGSUSED */
33742922Smckusick ioctl(p, uap, retval)
33842922Smckusick 	struct proc *p;
33954930Storek 	register struct ioctl_args *uap;
34042922Smckusick 	int *retval;
34142922Smckusick {
34242922Smckusick 	register struct file *fp;
34364538Sbostic 	register struct filedesc *fdp;
34440703Skarels 	register int com, error;
3457820Sroot 	register u_int size;
34664538Sbostic 	caddr_t data, memp;
34764538Sbostic 	int tmp;
34830530Skarels #define STK_PARAMS	128
34933480Skarels 	char stkbuf[STK_PARAMS];
3507423Sroot 
35164538Sbostic 	fdp = p->p_fd;
35264409Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
35364409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
35444405Skarels 		return (EBADF);
35564538Sbostic 
35664538Sbostic 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
35744405Skarels 		return (EBADF);
3587624Ssam 
35964538Sbostic 	switch (com = uap->com) {
36064538Sbostic 	case FIONCLEX:
36164538Sbostic 		fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE;
36264538Sbostic 		return (0);
36364538Sbostic 	case FIOCLEX:
36464409Sbostic 		fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE;
36544405Skarels 		return (0);
3667423Sroot 	}
3677624Ssam 
3687624Ssam 	/*
36964538Sbostic 	 * Interpret high order word to find amount of data to be
37064538Sbostic 	 * copied to/from the user's address space.
3717624Ssam 	 */
37230530Skarels 	size = IOCPARM_LEN(com);
37340703Skarels 	if (size > IOCPARM_MAX)
37444405Skarels 		return (ENOTTY);
37564538Sbostic 	memp = NULL;
37633480Skarels 	if (size > sizeof (stkbuf)) {
37743383Smckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
37831653Smckusick 		data = memp;
37964538Sbostic 	} else
38064538Sbostic 		data = stkbuf;
38110601Ssam 	if (com&IOC_IN) {
38210601Ssam 		if (size) {
38364409Sbostic 			error = copyin(uap->data, data, (u_int)size);
38440703Skarels 			if (error) {
38531653Smckusick 				if (memp)
38631653Smckusick 					free(memp, M_IOCTLOPS);
38744405Skarels 				return (error);
38831653Smckusick 			}
38910601Ssam 		} else
39064409Sbostic 			*(caddr_t *)data = uap->data;
39110601Ssam 	} else if ((com&IOC_OUT) && size)
39210601Ssam 		/*
39337127Skarels 		 * Zero the buffer so the user always
39437127Skarels 		 * gets back something deterministic.
39510601Ssam 		 */
39630530Skarels 		bzero(data, size);
39711284Ssam 	else if (com&IOC_VOID)
39864409Sbostic 		*(caddr_t *)data = uap->data;
3997423Sroot 
40012751Ssam 	switch (com) {
4017624Ssam 
40212751Ssam 	case FIONBIO:
40348027Smckusick 		if (tmp = *(int *)data)
40449941Smckusick 			fp->f_flag |= FNONBLOCK;
40548027Smckusick 		else
40649941Smckusick 			fp->f_flag &= ~FNONBLOCK;
40748027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
40830530Skarels 		break;
40912751Ssam 
41012751Ssam 	case FIOASYNC:
41148027Smckusick 		if (tmp = *(int *)data)
41248027Smckusick 			fp->f_flag |= FASYNC;
41348027Smckusick 		else
41448027Smckusick 			fp->f_flag &= ~FASYNC;
41548027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
41630530Skarels 		break;
41712751Ssam 
41812751Ssam 	case FIOSETOWN:
41948027Smckusick 		tmp = *(int *)data;
42048027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
42148027Smckusick 			((struct socket *)fp->f_data)->so_pgid = tmp;
42248027Smckusick 			error = 0;
42348027Smckusick 			break;
42448027Smckusick 		}
42548027Smckusick 		if (tmp <= 0) {
42648027Smckusick 			tmp = -tmp;
42748027Smckusick 		} else {
42848027Smckusick 			struct proc *p1 = pfind(tmp);
42948027Smckusick 			if (p1 == 0) {
43048027Smckusick 				error = ESRCH;
43148027Smckusick 				break;
43248027Smckusick 			}
43348027Smckusick 			tmp = p1->p_pgrp->pg_id;
43448027Smckusick 		}
43548027Smckusick 		error = (*fp->f_ops->fo_ioctl)
43648027Smckusick 			(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
43730530Skarels 		break;
43812751Ssam 
43912751Ssam 	case FIOGETOWN:
44048027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
44148027Smckusick 			error = 0;
44248027Smckusick 			*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
44348027Smckusick 			break;
44448027Smckusick 		}
44548027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
44648027Smckusick 		*(int *)data = -*(int *)data;
44730530Skarels 		break;
44848027Smckusick 
44930530Skarels 	default:
45047540Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
45130530Skarels 		/*
45230530Skarels 		 * Copy any data to user, size was
45330530Skarels 		 * already set and checked above.
45430530Skarels 		 */
45540703Skarels 		if (error == 0 && (com&IOC_OUT) && size)
45664409Sbostic 			error = copyout(data, uap->data, (u_int)size);
45730530Skarels 		break;
4587423Sroot 	}
45931653Smckusick 	if (memp)
46031653Smckusick 		free(memp, M_IOCTLOPS);
46144405Skarels 	return (error);
4627423Sroot }
4637423Sroot 
46449227Skarels int	selwait, nselcoll;
46517593Skarels 
4667423Sroot /*
46712751Ssam  * Select system call.
4687423Sroot  */
46954930Storek struct select_args {
47063864Smckusick 	u_int	nd;
47154930Storek 	fd_set	*in, *ou, *ex;
47254930Storek 	struct	timeval *tv;
47354930Storek };
47442922Smckusick select(p, uap, retval)
47542922Smckusick 	register struct proc *p;
47654930Storek 	register struct select_args *uap;
47742922Smckusick 	int *retval;
47842922Smckusick {
47923523Skarels 	fd_set ibits[3], obits[3];
48012751Ssam 	struct timeval atv;
48163864Smckusick 	int s, ncoll, error = 0, timo;
48263864Smckusick 	u_int ni;
48312751Ssam 
48426277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
48526277Skarels 	bzero((caddr_t)obits, sizeof(obits));
48663864Smckusick 	if (uap->nd > FD_SETSIZE)
48763864Smckusick 		return (EINVAL);
48847540Skarels 	if (uap->nd > p->p_fd->fd_nfiles)
48947540Skarels 		uap->nd = p->p_fd->fd_nfiles;	/* forgiving; slightly wrong */
49063864Smckusick 	ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask);
49112751Ssam 
49212751Ssam #define	getbits(name, x) \
49363864Smckusick 	if (uap->name && \
49463864Smckusick 	    (error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], ni))) \
49563864Smckusick 		goto done;
49612751Ssam 	getbits(in, 0);
49712751Ssam 	getbits(ou, 1);
49812751Ssam 	getbits(ex, 2);
49912751Ssam #undef	getbits
50012751Ssam 
50112751Ssam 	if (uap->tv) {
50240703Skarels 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
50312751Ssam 			sizeof (atv));
50440703Skarels 		if (error)
50512751Ssam 			goto done;
50612751Ssam 		if (itimerfix(&atv)) {
50740703Skarels 			error = EINVAL;
50812751Ssam 			goto done;
50912751Ssam 		}
51054760Storek 		s = splclock();
51154760Storek 		timevaladd(&atv, (struct timeval *)&time);
51240703Skarels 		timo = hzto(&atv);
51358254Smckusick 		/*
51458254Smckusick 		 * Avoid inadvertently sleeping forever.
51558254Smckusick 		 */
51658254Smckusick 		if (timo == 0)
51758254Smckusick 			timo = 1;
51854276Sbostic 		splx(s);
51940703Skarels 	} else
52040703Skarels 		timo = 0;
52112751Ssam retry:
52212751Ssam 	ncoll = nselcoll;
52364583Sbostic 	p->p_flag |= P_SELECT;
52447540Skarels 	error = selscan(p, ibits, obits, uap->nd, retval);
52542922Smckusick 	if (error || *retval)
52612751Ssam 		goto done;
52717934Skarels 	s = splhigh();
52812971Ssam 	/* this should be timercmp(&time, &atv, >=) */
52912971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
53012971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
53112751Ssam 		splx(s);
53212751Ssam 		goto done;
53312751Ssam 	}
53464583Sbostic 	if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
53512751Ssam 		splx(s);
53612751Ssam 		goto retry;
53712751Ssam 	}
53864583Sbostic 	p->p_flag &= ~P_SELECT;
53940703Skarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
54012751Ssam 	splx(s);
54140703Skarels 	if (error == 0)
54240703Skarels 		goto retry;
54312751Ssam done:
54464583Sbostic 	p->p_flag &= ~P_SELECT;
54540703Skarels 	/* select is not restarted after signals... */
54640703Skarels 	if (error == ERESTART)
54740703Skarels 		error = EINTR;
54840703Skarels 	if (error == EWOULDBLOCK)
54940703Skarels 		error = 0;
55012751Ssam #define	putbits(name, x) \
55163864Smckusick 	if (uap->name && \
55263864Smckusick 	    (error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, ni))) \
55363864Smckusick 		error = error2;
55440703Skarels 	if (error == 0) {
55563864Smckusick 		int error2;
55663864Smckusick 
55721106Skarels 		putbits(in, 0);
55821106Skarels 		putbits(ou, 1);
55921106Skarels 		putbits(ex, 2);
56012751Ssam #undef putbits
56121106Skarels 	}
56244405Skarels 	return (error);
56312751Ssam }
56412751Ssam 
56547540Skarels selscan(p, ibits, obits, nfd, retval)
56647540Skarels 	struct proc *p;
56723523Skarels 	fd_set *ibits, *obits;
56842922Smckusick 	int nfd, *retval;
56912751Ssam {
57047540Skarels 	register struct filedesc *fdp = p->p_fd;
57152481Storek 	register int msk, i, j, fd;
57223523Skarels 	register fd_mask bits;
57312751Ssam 	struct file *fp;
57452481Storek 	int n = 0;
57552481Storek 	static int flag[3] = { FREAD, FWRITE, 0 };
57612751Ssam 
57752481Storek 	for (msk = 0; msk < 3; msk++) {
57823523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
57952481Storek 			bits = ibits[msk].fds_bits[i/NFDBITS];
58052481Storek 			while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
58117593Skarels 				bits &= ~(1 << j);
58252481Storek 				fp = fdp->fd_ofiles[fd];
58352481Storek 				if (fp == NULL)
58452481Storek 					return (EBADF);
58552481Storek 				if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
58652481Storek 					FD_SET(fd, &obits[msk]);
58717593Skarels 					n++;
58817593Skarels 				}
58912751Ssam 			}
59012751Ssam 		}
59112751Ssam 	}
59242922Smckusick 	*retval = n;
59352481Storek 	return (0);
59412751Ssam }
59512751Ssam 
5967423Sroot /*ARGSUSED*/
59747540Skarels seltrue(dev, flag, p)
59812751Ssam 	dev_t dev;
59912751Ssam 	int flag;
60047540Skarels 	struct proc *p;
6017423Sroot {
6027423Sroot 
60312751Ssam 	return (1);
6047423Sroot }
6058103Sroot 
60652525Smckusick /*
60752525Smckusick  * Record a select request.
60852525Smckusick  */
60952525Smckusick void
61052525Smckusick selrecord(selector, sip)
61152525Smckusick 	struct proc *selector;
61252525Smckusick 	struct selinfo *sip;
6138103Sroot {
61452525Smckusick 	struct proc *p;
61552525Smckusick 	pid_t mypid;
6168103Sroot 
61752525Smckusick 	mypid = selector->p_pid;
61852525Smckusick 	if (sip->si_pid == mypid)
61952525Smckusick 		return;
62052525Smckusick 	if (sip->si_pid && (p = pfind(sip->si_pid)) &&
62152525Smckusick 	    p->p_wchan == (caddr_t)&selwait)
62252525Smckusick 		sip->si_flags |= SI_COLL;
62352525Smckusick 	else
62452525Smckusick 		sip->si_pid = mypid;
62552525Smckusick }
62652525Smckusick 
62752525Smckusick /*
62852525Smckusick  * Do a wakeup when a selectable event occurs.
62952525Smckusick  */
63052525Smckusick void
63152525Smckusick selwakeup(sip)
63252525Smckusick 	register struct selinfo *sip;
63352525Smckusick {
63452525Smckusick 	register struct proc *p;
63552525Smckusick 	int s;
63652525Smckusick 
63752525Smckusick 	if (sip->si_pid == 0)
63852525Smckusick 		return;
63952525Smckusick 	if (sip->si_flags & SI_COLL) {
64012751Ssam 		nselcoll++;
64152525Smckusick 		sip->si_flags &= ~SI_COLL;
64212751Ssam 		wakeup((caddr_t)&selwait);
64312751Ssam 	}
64452922Smckusick 	p = pfind(sip->si_pid);
64552922Smckusick 	sip->si_pid = 0;
64652922Smckusick 	if (p != NULL) {
64752525Smckusick 		s = splhigh();
64817270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
64917270Skarels 			if (p->p_stat == SSLEEP)
65064538Sbostic 				setrunnable(p);
65117270Skarels 			else
65217270Skarels 				unsleep(p);
65364583Sbostic 		} else if (p->p_flag & P_SELECT)
65464583Sbostic 			p->p_flag &= ~P_SELECT;
65512751Ssam 		splx(s);
65612751Ssam 	}
6578103Sroot }
658