xref: /csrg-svn/sys/kern/sys_generic.c (revision 67633)
123384Smckusick /*
263865Sbostic  * Copyright (c) 1982, 1986, 1989, 1993
363865Sbostic  *	The Regents of the University of California.  All rights reserved.
465771Sbostic  * (c) UNIX System Laboratories, Inc.
565771Sbostic  * All or some portions of this file are derived from material licensed
665771Sbostic  * to the University of California by American Telephone and Telegraph
765771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic  * the permission of UNIX System Laboratories, Inc.
923384Smckusick  *
1044444Sbostic  * %sccs.include.redist.c%
1137728Smckusick  *
12*67633Smckusick  *	@(#)sys_generic.c	8.7 (Berkeley) 08/10/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++) {
13567491Smckusick 		if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
13637728Smckusick 			error = EINVAL;
13737728Smckusick 			goto done;
13837728Smckusick 		}
13937728Smckusick 		auio.uio_resid += iov->iov_len;
14037728Smckusick 		iov++;
14137728Smckusick 	}
14237728Smckusick #ifdef KTRACE
14337728Smckusick 	/*
14437728Smckusick 	 * if tracing, save a copy of iovec
14537728Smckusick 	 */
14642922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
14737728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
14837728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
14937728Smckusick 	}
15037728Smckusick #endif
15137728Smckusick 	cnt = auio.uio_resid;
15240703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
15340703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
15440703Skarels 		    error == EINTR || error == EWOULDBLOCK))
15540703Skarels 			error = 0;
15637728Smckusick 	cnt -= auio.uio_resid;
15737728Smckusick #ifdef KTRACE
15837728Smckusick 	if (ktriov != NULL) {
15941178Smarc 		if (error == 0)
16043448Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
16143448Smckusick 			    cnt, error);
16237728Smckusick 		FREE(ktriov, M_TEMP);
16337728Smckusick 	}
16437728Smckusick #endif
16542922Smckusick 	*retval = cnt;
16637127Skarels done:
16752481Storek 	if (needfree)
16852481Storek 		FREE(needfree, M_IOV);
16944405Skarels 	return (error);
1707423Sroot }
1717423Sroot 
1727423Sroot /*
1737423Sroot  * Write system call
1747423Sroot  */
17554930Storek struct write_args {
17664409Sbostic 	int	fd;
17764409Sbostic 	char	*buf;
17864409Sbostic 	u_int	nbyte;
17954930Storek };
18042922Smckusick write(p, uap, retval)
18142922Smckusick 	struct proc *p;
18254930Storek 	register struct write_args *uap;
18342922Smckusick 	int *retval;
18442922Smckusick {
18537728Smckusick 	register struct file *fp;
18645914Smckusick 	register struct filedesc *fdp = p->p_fd;
1877820Sroot 	struct uio auio;
1887820Sroot 	struct iovec aiov;
18937728Smckusick 	long cnt, error = 0;
19037728Smckusick #ifdef KTRACE
19137728Smckusick 	struct iovec ktriov;
19237728Smckusick #endif
1937423Sroot 
19464409Sbostic 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
19564409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
19637728Smckusick 	    (fp->f_flag & FWRITE) == 0)
19744405Skarels 		return (EBADF);
19864409Sbostic 	aiov.iov_base = (caddr_t)uap->buf;
19964409Sbostic 	aiov.iov_len = uap->nbyte;
2007820Sroot 	auio.uio_iov = &aiov;
2017820Sroot 	auio.uio_iovcnt = 1;
20264409Sbostic 	auio.uio_resid = uap->nbyte;
20337728Smckusick 	auio.uio_rw = UIO_WRITE;
20437728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
20548027Smckusick 	auio.uio_procp = p;
20637728Smckusick #ifdef KTRACE
20737728Smckusick 	/*
20837728Smckusick 	 * if tracing, save a copy of iovec
20937728Smckusick 	 */
21042922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
21137728Smckusick 		ktriov = aiov;
21237728Smckusick #endif
21364409Sbostic 	cnt = uap->nbyte;
21440703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
21540703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
21640703Skarels 		    error == EINTR || error == EWOULDBLOCK))
21740703Skarels 			error = 0;
21840703Skarels 		if (error == EPIPE)
21942922Smckusick 			psignal(p, SIGPIPE);
22040703Skarels 	}
22137728Smckusick 	cnt -= auio.uio_resid;
22237728Smckusick #ifdef KTRACE
22342922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
22464409Sbostic 		ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
22543448Smckusick 		    &ktriov, cnt, error);
22637728Smckusick #endif
22742922Smckusick 	*retval = cnt;
22844405Skarels 	return (error);
2297820Sroot }
2307820Sroot 
23142922Smckusick /*
23242922Smckusick  * Gather write system call
23342922Smckusick  */
23454930Storek struct writev_args {
23564409Sbostic 	int	fd;
23654930Storek 	struct	iovec *iovp;
23764409Sbostic 	u_int	iovcnt;
23854930Storek };
23942922Smckusick writev(p, uap, retval)
24042922Smckusick 	struct proc *p;
24154930Storek 	register struct writev_args *uap;
24242922Smckusick 	int *retval;
24342922Smckusick {
24437728Smckusick 	register struct file *fp;
24545914Smckusick 	register struct filedesc *fdp = p->p_fd;
2467820Sroot 	struct uio auio;
24737728Smckusick 	register struct iovec *iov;
24852481Storek 	struct iovec *needfree;
24937728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
25037728Smckusick 	long i, cnt, error = 0;
25164409Sbostic 	u_int iovlen;
25237728Smckusick #ifdef KTRACE
25337728Smckusick 	struct iovec *ktriov = NULL;
25437728Smckusick #endif
2557820Sroot 
25664409Sbostic 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
25764409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
25837728Smckusick 	    (fp->f_flag & FWRITE) == 0)
25944405Skarels 		return (EBADF);
26044939Skarels 	/* note: can't use iovlen until iovcnt is validated */
26144939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
26237127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
26337728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
26444405Skarels 			return (EINVAL);
26544939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
26652481Storek 		needfree = iov;
26752481Storek 	} else {
26837127Skarels 		iov = aiov;
26952481Storek 		needfree = NULL;
27052481Storek 	}
27137127Skarels 	auio.uio_iov = iov;
2727820Sroot 	auio.uio_iovcnt = uap->iovcnt;
27337728Smckusick 	auio.uio_rw = UIO_WRITE;
27437728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
27548027Smckusick 	auio.uio_procp = p;
27644939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
27737127Skarels 		goto done;
27837728Smckusick 	auio.uio_resid = 0;
27937728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
28067491Smckusick 		if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
28137728Smckusick 			error = EINVAL;
28237728Smckusick 			goto done;
2837820Sroot 		}
28437728Smckusick 		auio.uio_resid += iov->iov_len;
28513270Ssam 		iov++;
2867820Sroot 	}
28737127Skarels #ifdef KTRACE
28837728Smckusick 	/*
28937728Smckusick 	 * if tracing, save a copy of iovec
29037728Smckusick 	 */
29142922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
29237127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
29337728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
29437127Skarels 	}
29537127Skarels #endif
29637728Smckusick 	cnt = auio.uio_resid;
29740703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
29840703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
29940703Skarels 		    error == EINTR || error == EWOULDBLOCK))
30040703Skarels 			error = 0;
30140703Skarels 		if (error == EPIPE)
30242922Smckusick 			psignal(p, SIGPIPE);
30340703Skarels 	}
30437728Smckusick 	cnt -= auio.uio_resid;
30537127Skarels #ifdef KTRACE
30637127Skarels 	if (ktriov != NULL) {
30741178Smarc 		if (error == 0)
30864409Sbostic 			ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
30943448Smckusick 				ktriov, cnt, error);
31037127Skarels 		FREE(ktriov, M_TEMP);
31137127Skarels 	}
31237127Skarels #endif
31342922Smckusick 	*retval = cnt;
31437728Smckusick done:
31552481Storek 	if (needfree)
31652481Storek 		FREE(needfree, M_IOV);
31744405Skarels 	return (error);
3187423Sroot }
3197423Sroot 
3207423Sroot /*
3217423Sroot  * Ioctl system call
3227423Sroot  */
32354930Storek struct ioctl_args {
32464409Sbostic 	int	fd;
32564409Sbostic 	int	com;
32664409Sbostic 	caddr_t	data;
32754930Storek };
32842922Smckusick /* ARGSUSED */
32942922Smckusick ioctl(p, uap, retval)
33042922Smckusick 	struct proc *p;
33154930Storek 	register struct ioctl_args *uap;
33242922Smckusick 	int *retval;
33342922Smckusick {
33442922Smckusick 	register struct file *fp;
33564538Sbostic 	register struct filedesc *fdp;
33640703Skarels 	register int com, error;
3377820Sroot 	register u_int size;
33864538Sbostic 	caddr_t data, memp;
33964538Sbostic 	int tmp;
34030530Skarels #define STK_PARAMS	128
34133480Skarels 	char stkbuf[STK_PARAMS];
3427423Sroot 
34364538Sbostic 	fdp = p->p_fd;
34464409Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
34564409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
34644405Skarels 		return (EBADF);
34764538Sbostic 
34864538Sbostic 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
34944405Skarels 		return (EBADF);
3507624Ssam 
35164538Sbostic 	switch (com = uap->com) {
35264538Sbostic 	case FIONCLEX:
35364538Sbostic 		fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE;
35464538Sbostic 		return (0);
35564538Sbostic 	case FIOCLEX:
35664409Sbostic 		fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE;
35744405Skarels 		return (0);
3587423Sroot 	}
3597624Ssam 
3607624Ssam 	/*
36164538Sbostic 	 * Interpret high order word to find amount of data to be
36264538Sbostic 	 * copied to/from the user's address space.
3637624Ssam 	 */
36430530Skarels 	size = IOCPARM_LEN(com);
36540703Skarels 	if (size > IOCPARM_MAX)
36644405Skarels 		return (ENOTTY);
36764538Sbostic 	memp = NULL;
36833480Skarels 	if (size > sizeof (stkbuf)) {
36943383Smckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
37031653Smckusick 		data = memp;
37164538Sbostic 	} else
37264538Sbostic 		data = stkbuf;
37310601Ssam 	if (com&IOC_IN) {
37410601Ssam 		if (size) {
37564409Sbostic 			error = copyin(uap->data, data, (u_int)size);
37640703Skarels 			if (error) {
37731653Smckusick 				if (memp)
37831653Smckusick 					free(memp, M_IOCTLOPS);
37944405Skarels 				return (error);
38031653Smckusick 			}
38110601Ssam 		} else
38264409Sbostic 			*(caddr_t *)data = uap->data;
38310601Ssam 	} else if ((com&IOC_OUT) && size)
38410601Ssam 		/*
38537127Skarels 		 * Zero the buffer so the user always
38637127Skarels 		 * gets back something deterministic.
38710601Ssam 		 */
38830530Skarels 		bzero(data, size);
38911284Ssam 	else if (com&IOC_VOID)
39064409Sbostic 		*(caddr_t *)data = uap->data;
3917423Sroot 
39212751Ssam 	switch (com) {
3937624Ssam 
39412751Ssam 	case FIONBIO:
39548027Smckusick 		if (tmp = *(int *)data)
39649941Smckusick 			fp->f_flag |= FNONBLOCK;
39748027Smckusick 		else
39849941Smckusick 			fp->f_flag &= ~FNONBLOCK;
39948027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
40030530Skarels 		break;
40112751Ssam 
40212751Ssam 	case FIOASYNC:
40348027Smckusick 		if (tmp = *(int *)data)
40448027Smckusick 			fp->f_flag |= FASYNC;
40548027Smckusick 		else
40648027Smckusick 			fp->f_flag &= ~FASYNC;
40748027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
40830530Skarels 		break;
40912751Ssam 
41012751Ssam 	case FIOSETOWN:
41148027Smckusick 		tmp = *(int *)data;
41248027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
41348027Smckusick 			((struct socket *)fp->f_data)->so_pgid = tmp;
41448027Smckusick 			error = 0;
41548027Smckusick 			break;
41648027Smckusick 		}
41748027Smckusick 		if (tmp <= 0) {
41848027Smckusick 			tmp = -tmp;
41948027Smckusick 		} else {
42048027Smckusick 			struct proc *p1 = pfind(tmp);
42148027Smckusick 			if (p1 == 0) {
42248027Smckusick 				error = ESRCH;
42348027Smckusick 				break;
42448027Smckusick 			}
42548027Smckusick 			tmp = p1->p_pgrp->pg_id;
42648027Smckusick 		}
42748027Smckusick 		error = (*fp->f_ops->fo_ioctl)
42848027Smckusick 			(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
42930530Skarels 		break;
43012751Ssam 
43112751Ssam 	case FIOGETOWN:
43248027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
43348027Smckusick 			error = 0;
43448027Smckusick 			*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
43548027Smckusick 			break;
43648027Smckusick 		}
43748027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
43848027Smckusick 		*(int *)data = -*(int *)data;
43930530Skarels 		break;
44048027Smckusick 
44130530Skarels 	default:
44247540Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
44330530Skarels 		/*
44430530Skarels 		 * Copy any data to user, size was
44530530Skarels 		 * already set and checked above.
44630530Skarels 		 */
44740703Skarels 		if (error == 0 && (com&IOC_OUT) && size)
44864409Sbostic 			error = copyout(data, uap->data, (u_int)size);
44930530Skarels 		break;
4507423Sroot 	}
45131653Smckusick 	if (memp)
45231653Smckusick 		free(memp, M_IOCTLOPS);
45344405Skarels 	return (error);
4547423Sroot }
4557423Sroot 
45649227Skarels int	selwait, nselcoll;
45717593Skarels 
4587423Sroot /*
45912751Ssam  * Select system call.
4607423Sroot  */
46154930Storek struct select_args {
46263864Smckusick 	u_int	nd;
46354930Storek 	fd_set	*in, *ou, *ex;
46454930Storek 	struct	timeval *tv;
46554930Storek };
46642922Smckusick select(p, uap, retval)
46742922Smckusick 	register struct proc *p;
46854930Storek 	register struct select_args *uap;
46942922Smckusick 	int *retval;
47042922Smckusick {
47123523Skarels 	fd_set ibits[3], obits[3];
47212751Ssam 	struct timeval atv;
473*67633Smckusick 	int s, ncoll, error = 0, timo, doblock;
47463864Smckusick 	u_int ni;
47512751Ssam 
47626277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
47726277Skarels 	bzero((caddr_t)obits, sizeof(obits));
47863864Smckusick 	if (uap->nd > FD_SETSIZE)
47963864Smckusick 		return (EINVAL);
48047540Skarels 	if (uap->nd > p->p_fd->fd_nfiles)
48147540Skarels 		uap->nd = p->p_fd->fd_nfiles;	/* forgiving; slightly wrong */
48263864Smckusick 	ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask);
48312751Ssam 
48412751Ssam #define	getbits(name, x) \
48563864Smckusick 	if (uap->name && \
48663864Smckusick 	    (error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], ni))) \
48763864Smckusick 		goto done;
48812751Ssam 	getbits(in, 0);
48912751Ssam 	getbits(ou, 1);
49012751Ssam 	getbits(ex, 2);
49112751Ssam #undef	getbits
49212751Ssam 
49312751Ssam 	if (uap->tv) {
49440703Skarels 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
49512751Ssam 			sizeof (atv));
49640703Skarels 		if (error)
49712751Ssam 			goto done;
49812751Ssam 		if (itimerfix(&atv)) {
49940703Skarels 			error = EINVAL;
50012751Ssam 			goto done;
50112751Ssam 		}
502*67633Smckusick 		/*
503*67633Smckusick 		 * Don't let a short time get rounded down to zero
504*67633Smckusick 		 * and cause us to sleep forever, but exactly zero
505*67633Smckusick 		 * means "do not block".
506*67633Smckusick 		 */
507*67633Smckusick 		doblock = (atv.tv_usec || atv.tv_sec);
50854760Storek 		s = splclock();
50954760Storek 		timevaladd(&atv, (struct timeval *)&time);
51054276Sbostic 		splx(s);
51140703Skarels 	} else
51240703Skarels 		timo = 0;
51312751Ssam retry:
51412751Ssam 	ncoll = nselcoll;
51564583Sbostic 	p->p_flag |= P_SELECT;
51647540Skarels 	error = selscan(p, ibits, obits, uap->nd, retval);
51742922Smckusick 	if (error || *retval)
51812751Ssam 		goto done;
51917934Skarels 	s = splhigh();
520*67633Smckusick 	if (uap->tv) {
521*67633Smckusick 		if (timercmp(&time, &atv, >=)) {
522*67633Smckusick 			splx(s);
523*67633Smckusick 			goto done;
524*67633Smckusick 		}
525*67633Smckusick 		timo = hzto(&atv);
526*67633Smckusick 		/*
527*67633Smckusick 		 * Avoid inadvertently sleeping forever.
528*67633Smckusick 		 */
529*67633Smckusick 		if (doblock && timo == 0)
530*67633Smckusick 			timo = 1;
53112751Ssam 	}
53264583Sbostic 	if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
53312751Ssam 		splx(s);
53412751Ssam 		goto retry;
53512751Ssam 	}
53664583Sbostic 	p->p_flag &= ~P_SELECT;
537*67633Smckusick 	doblock = 0;
53840703Skarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
53912751Ssam 	splx(s);
54040703Skarels 	if (error == 0)
54140703Skarels 		goto retry;
54212751Ssam done:
54364583Sbostic 	p->p_flag &= ~P_SELECT;
54440703Skarels 	/* select is not restarted after signals... */
54540703Skarels 	if (error == ERESTART)
54640703Skarels 		error = EINTR;
54740703Skarels 	if (error == EWOULDBLOCK)
54840703Skarels 		error = 0;
54912751Ssam #define	putbits(name, x) \
55063864Smckusick 	if (uap->name && \
55163864Smckusick 	    (error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, ni))) \
55263864Smckusick 		error = error2;
55340703Skarels 	if (error == 0) {
55463864Smckusick 		int error2;
55563864Smckusick 
55621106Skarels 		putbits(in, 0);
55721106Skarels 		putbits(ou, 1);
55821106Skarels 		putbits(ex, 2);
55912751Ssam #undef putbits
56021106Skarels 	}
56144405Skarels 	return (error);
56212751Ssam }
56312751Ssam 
56447540Skarels selscan(p, ibits, obits, nfd, retval)
56547540Skarels 	struct proc *p;
56623523Skarels 	fd_set *ibits, *obits;
56742922Smckusick 	int nfd, *retval;
56812751Ssam {
56947540Skarels 	register struct filedesc *fdp = p->p_fd;
57052481Storek 	register int msk, i, j, fd;
57123523Skarels 	register fd_mask bits;
57212751Ssam 	struct file *fp;
57352481Storek 	int n = 0;
57452481Storek 	static int flag[3] = { FREAD, FWRITE, 0 };
57512751Ssam 
57652481Storek 	for (msk = 0; msk < 3; msk++) {
57723523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
57852481Storek 			bits = ibits[msk].fds_bits[i/NFDBITS];
57952481Storek 			while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
58017593Skarels 				bits &= ~(1 << j);
58152481Storek 				fp = fdp->fd_ofiles[fd];
58252481Storek 				if (fp == NULL)
58352481Storek 					return (EBADF);
58452481Storek 				if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
58552481Storek 					FD_SET(fd, &obits[msk]);
58617593Skarels 					n++;
58717593Skarels 				}
58812751Ssam 			}
58912751Ssam 		}
59012751Ssam 	}
59142922Smckusick 	*retval = n;
59252481Storek 	return (0);
59312751Ssam }
59412751Ssam 
5957423Sroot /*ARGSUSED*/
59647540Skarels seltrue(dev, flag, p)
59712751Ssam 	dev_t dev;
59812751Ssam 	int flag;
59947540Skarels 	struct proc *p;
6007423Sroot {
6017423Sroot 
60212751Ssam 	return (1);
6037423Sroot }
6048103Sroot 
60552525Smckusick /*
60652525Smckusick  * Record a select request.
60752525Smckusick  */
60852525Smckusick void
60952525Smckusick selrecord(selector, sip)
61052525Smckusick 	struct proc *selector;
61152525Smckusick 	struct selinfo *sip;
6128103Sroot {
61352525Smckusick 	struct proc *p;
61452525Smckusick 	pid_t mypid;
6158103Sroot 
61652525Smckusick 	mypid = selector->p_pid;
61752525Smckusick 	if (sip->si_pid == mypid)
61852525Smckusick 		return;
61952525Smckusick 	if (sip->si_pid && (p = pfind(sip->si_pid)) &&
62052525Smckusick 	    p->p_wchan == (caddr_t)&selwait)
62152525Smckusick 		sip->si_flags |= SI_COLL;
62252525Smckusick 	else
62352525Smckusick 		sip->si_pid = mypid;
62452525Smckusick }
62552525Smckusick 
62652525Smckusick /*
62752525Smckusick  * Do a wakeup when a selectable event occurs.
62852525Smckusick  */
62952525Smckusick void
63052525Smckusick selwakeup(sip)
63152525Smckusick 	register struct selinfo *sip;
63252525Smckusick {
63352525Smckusick 	register struct proc *p;
63452525Smckusick 	int s;
63552525Smckusick 
63652525Smckusick 	if (sip->si_pid == 0)
63752525Smckusick 		return;
63852525Smckusick 	if (sip->si_flags & SI_COLL) {
63912751Ssam 		nselcoll++;
64052525Smckusick 		sip->si_flags &= ~SI_COLL;
64112751Ssam 		wakeup((caddr_t)&selwait);
64212751Ssam 	}
64352922Smckusick 	p = pfind(sip->si_pid);
64452922Smckusick 	sip->si_pid = 0;
64552922Smckusick 	if (p != NULL) {
64652525Smckusick 		s = splhigh();
64717270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
64817270Skarels 			if (p->p_stat == SSLEEP)
64964538Sbostic 				setrunnable(p);
65017270Skarels 			else
65117270Skarels 				unsleep(p);
65264583Sbostic 		} else if (p->p_flag & P_SELECT)
65364583Sbostic 			p->p_flag &= ~P_SELECT;
65412751Ssam 		splx(s);
65512751Ssam 	}
6568103Sroot }
657