xref: /csrg-svn/sys/kern/sys_generic.c (revision 64538)
123384Smckusick /*
263865Sbostic  * Copyright (c) 1982, 1986, 1989, 1993
363865Sbostic  *	The Regents of the University of California.  All rights reserved.
423384Smckusick  *
544444Sbostic  * %sccs.include.redist.c%
637728Smckusick  *
7*64538Sbostic  *	@(#)sys_generic.c	8.3 (Berkeley) 09/21/93
823384Smckusick  */
97423Sroot 
1056517Sbostic #include <sys/param.h>
1156517Sbostic #include <sys/systm.h>
1256517Sbostic #include <sys/filedesc.h>
1356517Sbostic #include <sys/ioctl.h>
1456517Sbostic #include <sys/file.h>
1556517Sbostic #include <sys/proc.h>
1656517Sbostic #include <sys/socketvar.h>
1756517Sbostic #include <sys/uio.h>
1856517Sbostic #include <sys/kernel.h>
1956517Sbostic #include <sys/stat.h>
2056517Sbostic #include <sys/malloc.h>
2137127Skarels #ifdef KTRACE
2256517Sbostic #include <sys/ktrace.h>
2337127Skarels #endif
247423Sroot 
257423Sroot /*
267423Sroot  * Read system call.
277423Sroot  */
2854930Storek struct read_args {
2964409Sbostic 	int	fd;
3064409Sbostic 	char	*buf;
3164409Sbostic 	u_int	nbyte;
3254930Storek };
3345122Sbostic /* ARGSUSED */
3442922Smckusick read(p, uap, retval)
3542922Smckusick 	struct proc *p;
3654930Storek 	register struct read_args *uap;
3742922Smckusick 	int *retval;
3842922Smckusick {
3937728Smckusick 	register struct file *fp;
4045914Smckusick 	register struct filedesc *fdp = p->p_fd;
417746Sroot 	struct uio auio;
427746Sroot 	struct iovec aiov;
4337728Smckusick 	long cnt, error = 0;
4437728Smckusick #ifdef KTRACE
4537728Smckusick 	struct iovec ktriov;
4637728Smckusick #endif
477423Sroot 
4864409Sbostic 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
4964409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
5037728Smckusick 	    (fp->f_flag & FREAD) == 0)
5144405Skarels 		return (EBADF);
5264409Sbostic 	aiov.iov_base = (caddr_t)uap->buf;
5364409Sbostic 	aiov.iov_len = uap->nbyte;
547820Sroot 	auio.uio_iov = &aiov;
557820Sroot 	auio.uio_iovcnt = 1;
5664409Sbostic 	auio.uio_resid = uap->nbyte;
5737728Smckusick 	auio.uio_rw = UIO_READ;
5837728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
5948027Smckusick 	auio.uio_procp = p;
6037728Smckusick #ifdef KTRACE
6137728Smckusick 	/*
6237728Smckusick 	 * if tracing, save a copy of iovec
6337728Smckusick 	 */
6442922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
6537728Smckusick 		ktriov = aiov;
6637728Smckusick #endif
6764409Sbostic 	cnt = uap->nbyte;
6840703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
6940703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
7040703Skarels 		    error == EINTR || error == EWOULDBLOCK))
7140703Skarels 			error = 0;
7237728Smckusick 	cnt -= auio.uio_resid;
7337728Smckusick #ifdef KTRACE
7442922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
7564409Sbostic 		ktrgenio(p->p_tracep, uap->fd, UIO_READ, &ktriov, cnt, error);
7637728Smckusick #endif
7742922Smckusick 	*retval = cnt;
7844405Skarels 	return (error);
797820Sroot }
807820Sroot 
8142922Smckusick /*
8242922Smckusick  * Scatter read system call.
8342922Smckusick  */
8454930Storek struct readv_args {
8554930Storek 	int	fdes;
8654930Storek 	struct	iovec *iovp;
8764409Sbostic 	u_int	iovcnt;
8854930Storek };
8942922Smckusick readv(p, uap, retval)
9042922Smckusick 	struct proc *p;
9154930Storek 	register struct readv_args *uap;
9242922Smckusick 	int *retval;
9342922Smckusick {
9437728Smckusick 	register struct file *fp;
9545914Smckusick 	register struct filedesc *fdp = p->p_fd;
967820Sroot 	struct uio auio;
9737728Smckusick 	register struct iovec *iov;
9852481Storek 	struct iovec *needfree;
9937728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
10037728Smckusick 	long i, cnt, error = 0;
10164409Sbostic 	u_int iovlen;
10237728Smckusick #ifdef KTRACE
10337728Smckusick 	struct iovec *ktriov = NULL;
10437728Smckusick #endif
1057820Sroot 
10664409Sbostic 	if (((u_int)uap->fdes) >= fdp->fd_nfiles ||
10747974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
10837728Smckusick 	    (fp->f_flag & FREAD) == 0)
10944405Skarels 		return (EBADF);
11044939Skarels 	/* note: can't use iovlen until iovcnt is validated */
11144939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
11237127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
11337728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
11444405Skarels 			return (EINVAL);
11544939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
11652481Storek 		needfree = iov;
11752481Storek 	} else {
11837127Skarels 		iov = aiov;
11952481Storek 		needfree = NULL;
12052481Storek 	}
12137127Skarels 	auio.uio_iov = iov;
1227820Sroot 	auio.uio_iovcnt = uap->iovcnt;
12337728Smckusick 	auio.uio_rw = UIO_READ;
12437728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
12548027Smckusick 	auio.uio_procp = p;
12644939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
12737127Skarels 		goto done;
12837728Smckusick 	auio.uio_resid = 0;
12937728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
13037728Smckusick 		if (iov->iov_len < 0) {
13137728Smckusick 			error = EINVAL;
13237728Smckusick 			goto done;
13337728Smckusick 		}
13437728Smckusick 		auio.uio_resid += iov->iov_len;
13537728Smckusick 		if (auio.uio_resid < 0) {
13637728Smckusick 			error = EINVAL;
13737728Smckusick 			goto done;
13837728Smckusick 		}
13937728Smckusick 		iov++;
14037728Smckusick 	}
14137728Smckusick #ifdef KTRACE
14237728Smckusick 	/*
14337728Smckusick 	 * if tracing, save a copy of iovec
14437728Smckusick 	 */
14542922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
14637728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
14737728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
14837728Smckusick 	}
14937728Smckusick #endif
15037728Smckusick 	cnt = auio.uio_resid;
15140703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
15240703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
15340703Skarels 		    error == EINTR || error == EWOULDBLOCK))
15440703Skarels 			error = 0;
15537728Smckusick 	cnt -= auio.uio_resid;
15637728Smckusick #ifdef KTRACE
15737728Smckusick 	if (ktriov != NULL) {
15841178Smarc 		if (error == 0)
15943448Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
16043448Smckusick 			    cnt, error);
16137728Smckusick 		FREE(ktriov, M_TEMP);
16237728Smckusick 	}
16337728Smckusick #endif
16442922Smckusick 	*retval = cnt;
16537127Skarels done:
16652481Storek 	if (needfree)
16752481Storek 		FREE(needfree, M_IOV);
16844405Skarels 	return (error);
1697423Sroot }
1707423Sroot 
1717423Sroot /*
1727423Sroot  * Write system call
1737423Sroot  */
17454930Storek struct write_args {
17564409Sbostic 	int	fd;
17664409Sbostic 	char	*buf;
17764409Sbostic 	u_int	nbyte;
17854930Storek };
17942922Smckusick write(p, uap, retval)
18042922Smckusick 	struct proc *p;
18154930Storek 	register struct write_args *uap;
18242922Smckusick 	int *retval;
18342922Smckusick {
18437728Smckusick 	register struct file *fp;
18545914Smckusick 	register struct filedesc *fdp = p->p_fd;
1867820Sroot 	struct uio auio;
1877820Sroot 	struct iovec aiov;
18837728Smckusick 	long cnt, error = 0;
18937728Smckusick #ifdef KTRACE
19037728Smckusick 	struct iovec ktriov;
19137728Smckusick #endif
1927423Sroot 
19364409Sbostic 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
19464409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
19537728Smckusick 	    (fp->f_flag & FWRITE) == 0)
19644405Skarels 		return (EBADF);
19764409Sbostic 	aiov.iov_base = (caddr_t)uap->buf;
19864409Sbostic 	aiov.iov_len = uap->nbyte;
1997820Sroot 	auio.uio_iov = &aiov;
2007820Sroot 	auio.uio_iovcnt = 1;
20164409Sbostic 	auio.uio_resid = uap->nbyte;
20237728Smckusick 	auio.uio_rw = UIO_WRITE;
20337728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
20448027Smckusick 	auio.uio_procp = p;
20537728Smckusick #ifdef KTRACE
20637728Smckusick 	/*
20737728Smckusick 	 * if tracing, save a copy of iovec
20837728Smckusick 	 */
20942922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
21037728Smckusick 		ktriov = aiov;
21137728Smckusick #endif
21264409Sbostic 	cnt = uap->nbyte;
21340703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
21440703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
21540703Skarels 		    error == EINTR || error == EWOULDBLOCK))
21640703Skarels 			error = 0;
21740703Skarels 		if (error == EPIPE)
21842922Smckusick 			psignal(p, SIGPIPE);
21940703Skarels 	}
22037728Smckusick 	cnt -= auio.uio_resid;
22137728Smckusick #ifdef KTRACE
22242922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
22364409Sbostic 		ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
22443448Smckusick 		    &ktriov, cnt, error);
22537728Smckusick #endif
22642922Smckusick 	*retval = cnt;
22744405Skarels 	return (error);
2287820Sroot }
2297820Sroot 
23042922Smckusick /*
23142922Smckusick  * Gather write system call
23242922Smckusick  */
23354930Storek struct writev_args {
23464409Sbostic 	int	fd;
23554930Storek 	struct	iovec *iovp;
23664409Sbostic 	u_int	iovcnt;
23754930Storek };
23842922Smckusick writev(p, uap, retval)
23942922Smckusick 	struct proc *p;
24054930Storek 	register struct writev_args *uap;
24142922Smckusick 	int *retval;
24242922Smckusick {
24337728Smckusick 	register struct file *fp;
24445914Smckusick 	register struct filedesc *fdp = p->p_fd;
2457820Sroot 	struct uio auio;
24637728Smckusick 	register struct iovec *iov;
24752481Storek 	struct iovec *needfree;
24837728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
24937728Smckusick 	long i, cnt, error = 0;
25064409Sbostic 	u_int iovlen;
25137728Smckusick #ifdef KTRACE
25237728Smckusick 	struct iovec *ktriov = NULL;
25337728Smckusick #endif
2547820Sroot 
25564409Sbostic 	if (((u_int)uap->fd) >= fdp->fd_nfiles ||
25664409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
25737728Smckusick 	    (fp->f_flag & FWRITE) == 0)
25844405Skarels 		return (EBADF);
25944939Skarels 	/* note: can't use iovlen until iovcnt is validated */
26044939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
26137127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
26237728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
26344405Skarels 			return (EINVAL);
26444939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
26552481Storek 		needfree = iov;
26652481Storek 	} else {
26737127Skarels 		iov = aiov;
26852481Storek 		needfree = NULL;
26952481Storek 	}
27037127Skarels 	auio.uio_iov = iov;
2717820Sroot 	auio.uio_iovcnt = uap->iovcnt;
27237728Smckusick 	auio.uio_rw = UIO_WRITE;
27337728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
27448027Smckusick 	auio.uio_procp = p;
27544939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
27637127Skarels 		goto done;
27737728Smckusick 	auio.uio_resid = 0;
27837728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
2797820Sroot 		if (iov->iov_len < 0) {
28037728Smckusick 			error = EINVAL;
28137728Smckusick 			goto done;
2827820Sroot 		}
28337728Smckusick 		auio.uio_resid += iov->iov_len;
28437728Smckusick 		if (auio.uio_resid < 0) {
28537728Smckusick 			error = EINVAL;
28637728Smckusick 			goto done;
2877820Sroot 		}
28813270Ssam 		iov++;
2897820Sroot 	}
29037127Skarels #ifdef KTRACE
29137728Smckusick 	/*
29237728Smckusick 	 * if tracing, save a copy of iovec
29337728Smckusick 	 */
29442922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
29537127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
29637728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
29737127Skarels 	}
29837127Skarels #endif
29937728Smckusick 	cnt = auio.uio_resid;
30040703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
30140703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
30240703Skarels 		    error == EINTR || error == EWOULDBLOCK))
30340703Skarels 			error = 0;
30440703Skarels 		if (error == EPIPE)
30542922Smckusick 			psignal(p, SIGPIPE);
30640703Skarels 	}
30737728Smckusick 	cnt -= auio.uio_resid;
30837127Skarels #ifdef KTRACE
30937127Skarels 	if (ktriov != NULL) {
31041178Smarc 		if (error == 0)
31164409Sbostic 			ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
31243448Smckusick 				ktriov, cnt, error);
31337127Skarels 		FREE(ktriov, M_TEMP);
31437127Skarels 	}
31537127Skarels #endif
31642922Smckusick 	*retval = cnt;
31737728Smckusick done:
31852481Storek 	if (needfree)
31952481Storek 		FREE(needfree, M_IOV);
32044405Skarels 	return (error);
3217423Sroot }
3227423Sroot 
3237423Sroot /*
3247423Sroot  * Ioctl system call
3257423Sroot  */
32654930Storek struct ioctl_args {
32764409Sbostic 	int	fd;
32864409Sbostic 	int	com;
32964409Sbostic 	caddr_t	data;
33054930Storek };
33142922Smckusick /* ARGSUSED */
33242922Smckusick ioctl(p, uap, retval)
33342922Smckusick 	struct proc *p;
33454930Storek 	register struct ioctl_args *uap;
33542922Smckusick 	int *retval;
33642922Smckusick {
33742922Smckusick 	register struct file *fp;
338*64538Sbostic 	register struct filedesc *fdp;
33940703Skarels 	register int com, error;
3407820Sroot 	register u_int size;
341*64538Sbostic 	caddr_t data, memp;
342*64538Sbostic 	int tmp;
34330530Skarels #define STK_PARAMS	128
34433480Skarels 	char stkbuf[STK_PARAMS];
3457423Sroot 
346*64538Sbostic 	fdp = p->p_fd;
34764409Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
34864409Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
34944405Skarels 		return (EBADF);
350*64538Sbostic 
351*64538Sbostic 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
35244405Skarels 		return (EBADF);
3537624Ssam 
354*64538Sbostic 	switch (com = uap->com) {
355*64538Sbostic 	case FIONCLEX:
356*64538Sbostic 		fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE;
357*64538Sbostic 		return (0);
358*64538Sbostic 	case FIOCLEX:
35964409Sbostic 		fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE;
36044405Skarels 		return (0);
3617423Sroot 	}
3627624Ssam 
3637624Ssam 	/*
364*64538Sbostic 	 * Interpret high order word to find amount of data to be
365*64538Sbostic 	 * copied to/from the user's address space.
3667624Ssam 	 */
36730530Skarels 	size = IOCPARM_LEN(com);
36840703Skarels 	if (size > IOCPARM_MAX)
36944405Skarels 		return (ENOTTY);
370*64538Sbostic 	memp = NULL;
37133480Skarels 	if (size > sizeof (stkbuf)) {
37243383Smckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
37331653Smckusick 		data = memp;
374*64538Sbostic 	} else
375*64538Sbostic 		data = stkbuf;
37610601Ssam 	if (com&IOC_IN) {
37710601Ssam 		if (size) {
37864409Sbostic 			error = copyin(uap->data, data, (u_int)size);
37940703Skarels 			if (error) {
38031653Smckusick 				if (memp)
38131653Smckusick 					free(memp, M_IOCTLOPS);
38244405Skarels 				return (error);
38331653Smckusick 			}
38410601Ssam 		} else
38564409Sbostic 			*(caddr_t *)data = uap->data;
38610601Ssam 	} else if ((com&IOC_OUT) && size)
38710601Ssam 		/*
38837127Skarels 		 * Zero the buffer so the user always
38937127Skarels 		 * gets back something deterministic.
39010601Ssam 		 */
39130530Skarels 		bzero(data, size);
39211284Ssam 	else if (com&IOC_VOID)
39364409Sbostic 		*(caddr_t *)data = uap->data;
3947423Sroot 
39512751Ssam 	switch (com) {
3967624Ssam 
39712751Ssam 	case FIONBIO:
39848027Smckusick 		if (tmp = *(int *)data)
39949941Smckusick 			fp->f_flag |= FNONBLOCK;
40048027Smckusick 		else
40149941Smckusick 			fp->f_flag &= ~FNONBLOCK;
40248027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
40330530Skarels 		break;
40412751Ssam 
40512751Ssam 	case FIOASYNC:
40648027Smckusick 		if (tmp = *(int *)data)
40748027Smckusick 			fp->f_flag |= FASYNC;
40848027Smckusick 		else
40948027Smckusick 			fp->f_flag &= ~FASYNC;
41048027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
41130530Skarels 		break;
41212751Ssam 
41312751Ssam 	case FIOSETOWN:
41448027Smckusick 		tmp = *(int *)data;
41548027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
41648027Smckusick 			((struct socket *)fp->f_data)->so_pgid = tmp;
41748027Smckusick 			error = 0;
41848027Smckusick 			break;
41948027Smckusick 		}
42048027Smckusick 		if (tmp <= 0) {
42148027Smckusick 			tmp = -tmp;
42248027Smckusick 		} else {
42348027Smckusick 			struct proc *p1 = pfind(tmp);
42448027Smckusick 			if (p1 == 0) {
42548027Smckusick 				error = ESRCH;
42648027Smckusick 				break;
42748027Smckusick 			}
42848027Smckusick 			tmp = p1->p_pgrp->pg_id;
42948027Smckusick 		}
43048027Smckusick 		error = (*fp->f_ops->fo_ioctl)
43148027Smckusick 			(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
43230530Skarels 		break;
43312751Ssam 
43412751Ssam 	case FIOGETOWN:
43548027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
43648027Smckusick 			error = 0;
43748027Smckusick 			*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
43848027Smckusick 			break;
43948027Smckusick 		}
44048027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
44148027Smckusick 		*(int *)data = -*(int *)data;
44230530Skarels 		break;
44348027Smckusick 
44430530Skarels 	default:
44547540Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
44630530Skarels 		/*
44730530Skarels 		 * Copy any data to user, size was
44830530Skarels 		 * already set and checked above.
44930530Skarels 		 */
45040703Skarels 		if (error == 0 && (com&IOC_OUT) && size)
45164409Sbostic 			error = copyout(data, uap->data, (u_int)size);
45230530Skarels 		break;
4537423Sroot 	}
45431653Smckusick 	if (memp)
45531653Smckusick 		free(memp, M_IOCTLOPS);
45644405Skarels 	return (error);
4577423Sroot }
4587423Sroot 
45949227Skarels int	selwait, nselcoll;
46017593Skarels 
4617423Sroot /*
46212751Ssam  * Select system call.
4637423Sroot  */
46454930Storek struct select_args {
46563864Smckusick 	u_int	nd;
46654930Storek 	fd_set	*in, *ou, *ex;
46754930Storek 	struct	timeval *tv;
46854930Storek };
46942922Smckusick select(p, uap, retval)
47042922Smckusick 	register struct proc *p;
47154930Storek 	register struct select_args *uap;
47242922Smckusick 	int *retval;
47342922Smckusick {
47423523Skarels 	fd_set ibits[3], obits[3];
47512751Ssam 	struct timeval atv;
47663864Smckusick 	int s, ncoll, error = 0, timo;
47763864Smckusick 	u_int ni;
47812751Ssam 
47926277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
48026277Skarels 	bzero((caddr_t)obits, sizeof(obits));
48163864Smckusick 	if (uap->nd > FD_SETSIZE)
48263864Smckusick 		return (EINVAL);
48347540Skarels 	if (uap->nd > p->p_fd->fd_nfiles)
48447540Skarels 		uap->nd = p->p_fd->fd_nfiles;	/* forgiving; slightly wrong */
48563864Smckusick 	ni = howmany(uap->nd, NFDBITS) * sizeof(fd_mask);
48612751Ssam 
48712751Ssam #define	getbits(name, x) \
48863864Smckusick 	if (uap->name && \
48963864Smckusick 	    (error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], ni))) \
49063864Smckusick 		goto done;
49112751Ssam 	getbits(in, 0);
49212751Ssam 	getbits(ou, 1);
49312751Ssam 	getbits(ex, 2);
49412751Ssam #undef	getbits
49512751Ssam 
49612751Ssam 	if (uap->tv) {
49740703Skarels 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
49812751Ssam 			sizeof (atv));
49940703Skarels 		if (error)
50012751Ssam 			goto done;
50112751Ssam 		if (itimerfix(&atv)) {
50240703Skarels 			error = EINVAL;
50312751Ssam 			goto done;
50412751Ssam 		}
50554760Storek 		s = splclock();
50654760Storek 		timevaladd(&atv, (struct timeval *)&time);
50740703Skarels 		timo = hzto(&atv);
50858254Smckusick 		/*
50958254Smckusick 		 * Avoid inadvertently sleeping forever.
51058254Smckusick 		 */
51158254Smckusick 		if (timo == 0)
51258254Smckusick 			timo = 1;
51354276Sbostic 		splx(s);
51440703Skarels 	} else
51540703Skarels 		timo = 0;
51612751Ssam retry:
51712751Ssam 	ncoll = nselcoll;
51842922Smckusick 	p->p_flag |= SSEL;
51947540Skarels 	error = selscan(p, ibits, obits, uap->nd, retval);
52042922Smckusick 	if (error || *retval)
52112751Ssam 		goto done;
52217934Skarels 	s = splhigh();
52312971Ssam 	/* this should be timercmp(&time, &atv, >=) */
52412971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
52512971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
52612751Ssam 		splx(s);
52712751Ssam 		goto done;
52812751Ssam 	}
52942922Smckusick 	if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
53012751Ssam 		splx(s);
53112751Ssam 		goto retry;
53212751Ssam 	}
53342922Smckusick 	p->p_flag &= ~SSEL;
53440703Skarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
53512751Ssam 	splx(s);
53640703Skarels 	if (error == 0)
53740703Skarels 		goto retry;
53812751Ssam done:
53942922Smckusick 	p->p_flag &= ~SSEL;
54040703Skarels 	/* select is not restarted after signals... */
54140703Skarels 	if (error == ERESTART)
54240703Skarels 		error = EINTR;
54340703Skarels 	if (error == EWOULDBLOCK)
54440703Skarels 		error = 0;
54512751Ssam #define	putbits(name, x) \
54663864Smckusick 	if (uap->name && \
54763864Smckusick 	    (error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, ni))) \
54863864Smckusick 		error = error2;
54940703Skarels 	if (error == 0) {
55063864Smckusick 		int error2;
55163864Smckusick 
55221106Skarels 		putbits(in, 0);
55321106Skarels 		putbits(ou, 1);
55421106Skarels 		putbits(ex, 2);
55512751Ssam #undef putbits
55621106Skarels 	}
55744405Skarels 	return (error);
55812751Ssam }
55912751Ssam 
56047540Skarels selscan(p, ibits, obits, nfd, retval)
56147540Skarels 	struct proc *p;
56223523Skarels 	fd_set *ibits, *obits;
56342922Smckusick 	int nfd, *retval;
56412751Ssam {
56547540Skarels 	register struct filedesc *fdp = p->p_fd;
56652481Storek 	register int msk, i, j, fd;
56723523Skarels 	register fd_mask bits;
56812751Ssam 	struct file *fp;
56952481Storek 	int n = 0;
57052481Storek 	static int flag[3] = { FREAD, FWRITE, 0 };
57112751Ssam 
57252481Storek 	for (msk = 0; msk < 3; msk++) {
57323523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
57452481Storek 			bits = ibits[msk].fds_bits[i/NFDBITS];
57552481Storek 			while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
57617593Skarels 				bits &= ~(1 << j);
57752481Storek 				fp = fdp->fd_ofiles[fd];
57852481Storek 				if (fp == NULL)
57952481Storek 					return (EBADF);
58052481Storek 				if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
58152481Storek 					FD_SET(fd, &obits[msk]);
58217593Skarels 					n++;
58317593Skarels 				}
58412751Ssam 			}
58512751Ssam 		}
58612751Ssam 	}
58742922Smckusick 	*retval = n;
58852481Storek 	return (0);
58912751Ssam }
59012751Ssam 
5917423Sroot /*ARGSUSED*/
59247540Skarels seltrue(dev, flag, p)
59312751Ssam 	dev_t dev;
59412751Ssam 	int flag;
59547540Skarels 	struct proc *p;
5967423Sroot {
5977423Sroot 
59812751Ssam 	return (1);
5997423Sroot }
6008103Sroot 
60152525Smckusick /*
60252525Smckusick  * Record a select request.
60352525Smckusick  */
60452525Smckusick void
60552525Smckusick selrecord(selector, sip)
60652525Smckusick 	struct proc *selector;
60752525Smckusick 	struct selinfo *sip;
6088103Sroot {
60952525Smckusick 	struct proc *p;
61052525Smckusick 	pid_t mypid;
6118103Sroot 
61252525Smckusick 	mypid = selector->p_pid;
61352525Smckusick 	if (sip->si_pid == mypid)
61452525Smckusick 		return;
61552525Smckusick 	if (sip->si_pid && (p = pfind(sip->si_pid)) &&
61652525Smckusick 	    p->p_wchan == (caddr_t)&selwait)
61752525Smckusick 		sip->si_flags |= SI_COLL;
61852525Smckusick 	else
61952525Smckusick 		sip->si_pid = mypid;
62052525Smckusick }
62152525Smckusick 
62252525Smckusick /*
62352525Smckusick  * Do a wakeup when a selectable event occurs.
62452525Smckusick  */
62552525Smckusick void
62652525Smckusick selwakeup(sip)
62752525Smckusick 	register struct selinfo *sip;
62852525Smckusick {
62952525Smckusick 	register struct proc *p;
63052525Smckusick 	int s;
63152525Smckusick 
63252525Smckusick 	if (sip->si_pid == 0)
63352525Smckusick 		return;
63452525Smckusick 	if (sip->si_flags & SI_COLL) {
63512751Ssam 		nselcoll++;
63652525Smckusick 		sip->si_flags &= ~SI_COLL;
63712751Ssam 		wakeup((caddr_t)&selwait);
63812751Ssam 	}
63952922Smckusick 	p = pfind(sip->si_pid);
64052922Smckusick 	sip->si_pid = 0;
64152922Smckusick 	if (p != NULL) {
64252525Smckusick 		s = splhigh();
64317270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
64417270Skarels 			if (p->p_stat == SSLEEP)
645*64538Sbostic 				setrunnable(p);
64617270Skarels 			else
64717270Skarels 				unsleep(p);
64817270Skarels 		} else if (p->p_flag & SSEL)
64912751Ssam 			p->p_flag &= ~SSEL;
65012751Ssam 		splx(s);
65112751Ssam 	}
6528103Sroot }
653