xref: /csrg-svn/sys/kern/sys_generic.c (revision 52525)
123384Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423384Smckusick  *
544444Sbostic  * %sccs.include.redist.c%
637728Smckusick  *
7*52525Smckusick  *	@(#)sys_generic.c	7.32 (Berkeley) 02/15/92
823384Smckusick  */
97423Sroot 
1017094Sbloom #include "param.h"
1117094Sbloom #include "systm.h"
1245914Smckusick #include "filedesc.h"
1317094Sbloom #include "ioctl.h"
1417094Sbloom #include "file.h"
15*52525Smckusick #include "proc.h"
1648027Smckusick #include "socketvar.h"
1717094Sbloom #include "uio.h"
1817094Sbloom #include "kernel.h"
1917094Sbloom #include "stat.h"
2031653Smckusick #include "malloc.h"
2137127Skarels #ifdef KTRACE
2237127Skarels #include "ktrace.h"
2337127Skarels #endif
247423Sroot 
257423Sroot /*
267423Sroot  * Read system call.
277423Sroot  */
2845122Sbostic /* ARGSUSED */
2942922Smckusick read(p, uap, retval)
3042922Smckusick 	struct proc *p;
3142922Smckusick 	register struct args {
327423Sroot 		int	fdes;
337423Sroot 		char	*cbuf;
347423Sroot 		unsigned count;
3542922Smckusick 	} *uap;
3642922Smckusick 	int *retval;
3742922Smckusick {
3837728Smckusick 	register struct file *fp;
3945914Smckusick 	register struct filedesc *fdp = p->p_fd;
407746Sroot 	struct uio auio;
417746Sroot 	struct iovec aiov;
4237728Smckusick 	long cnt, error = 0;
4337728Smckusick #ifdef KTRACE
4437728Smckusick 	struct iovec ktriov;
4537728Smckusick #endif
467423Sroot 
4747540Skarels 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
4847974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
4937728Smckusick 	    (fp->f_flag & FREAD) == 0)
5044405Skarels 		return (EBADF);
517820Sroot 	aiov.iov_base = (caddr_t)uap->cbuf;
527820Sroot 	aiov.iov_len = uap->count;
537820Sroot 	auio.uio_iov = &aiov;
547820Sroot 	auio.uio_iovcnt = 1;
5537728Smckusick 	auio.uio_resid = uap->count;
5637728Smckusick 	auio.uio_rw = UIO_READ;
5737728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
5848027Smckusick 	auio.uio_procp = p;
5937728Smckusick #ifdef KTRACE
6037728Smckusick 	/*
6137728Smckusick 	 * if tracing, save a copy of iovec
6237728Smckusick 	 */
6342922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
6437728Smckusick 		ktriov = aiov;
6537728Smckusick #endif
6637728Smckusick 	cnt = uap->count;
6740703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
6840703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
6940703Skarels 		    error == EINTR || error == EWOULDBLOCK))
7040703Skarels 			error = 0;
7137728Smckusick 	cnt -= auio.uio_resid;
7237728Smckusick #ifdef KTRACE
7342922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
7443448Smckusick 		ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
7537728Smckusick #endif
7642922Smckusick 	*retval = cnt;
7744405Skarels 	return (error);
787820Sroot }
797820Sroot 
8042922Smckusick /*
8142922Smckusick  * Scatter read system call.
8242922Smckusick  */
8345122Sbostic /* ARGSUSED */
8442922Smckusick readv(p, uap, retval)
8542922Smckusick 	struct proc *p;
8642922Smckusick 	register struct args {
877820Sroot 		int	fdes;
887820Sroot 		struct	iovec *iovp;
8926474Skarels 		unsigned iovcnt;
9042922Smckusick 	} *uap;
9142922Smckusick 	int *retval;
9242922Smckusick {
9337728Smckusick 	register struct file *fp;
9445914Smckusick 	register struct filedesc *fdp = p->p_fd;
957820Sroot 	struct uio auio;
9637728Smckusick 	register struct iovec *iov;
9752481Storek 	struct iovec *needfree;
9837728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
9937728Smckusick 	long i, cnt, error = 0;
10044939Skarels 	unsigned iovlen;
10137728Smckusick #ifdef KTRACE
10237728Smckusick 	struct iovec *ktriov = NULL;
10337728Smckusick #endif
1047820Sroot 
10547540Skarels 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
10647974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
10737728Smckusick 	    (fp->f_flag & FREAD) == 0)
10844405Skarels 		return (EBADF);
10944939Skarels 	/* note: can't use iovlen until iovcnt is validated */
11044939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
11137127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
11237728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
11344405Skarels 			return (EINVAL);
11444939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
11552481Storek 		needfree = iov;
11652481Storek 	} else {
11737127Skarels 		iov = aiov;
11852481Storek 		needfree = NULL;
11952481Storek 	}
12037127Skarels 	auio.uio_iov = iov;
1217820Sroot 	auio.uio_iovcnt = uap->iovcnt;
12237728Smckusick 	auio.uio_rw = UIO_READ;
12337728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
12448027Smckusick 	auio.uio_procp = p;
12544939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
12637127Skarels 		goto done;
12737728Smckusick 	auio.uio_resid = 0;
12837728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
12937728Smckusick 		if (iov->iov_len < 0) {
13037728Smckusick 			error = EINVAL;
13137728Smckusick 			goto done;
13237728Smckusick 		}
13337728Smckusick 		auio.uio_resid += iov->iov_len;
13437728Smckusick 		if (auio.uio_resid < 0) {
13537728Smckusick 			error = EINVAL;
13637728Smckusick 			goto done;
13737728Smckusick 		}
13837728Smckusick 		iov++;
13937728Smckusick 	}
14037728Smckusick #ifdef KTRACE
14137728Smckusick 	/*
14237728Smckusick 	 * if tracing, save a copy of iovec
14337728Smckusick 	 */
14442922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
14537728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
14637728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
14737728Smckusick 	}
14837728Smckusick #endif
14937728Smckusick 	cnt = auio.uio_resid;
15040703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
15140703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
15240703Skarels 		    error == EINTR || error == EWOULDBLOCK))
15340703Skarels 			error = 0;
15437728Smckusick 	cnt -= auio.uio_resid;
15537728Smckusick #ifdef KTRACE
15637728Smckusick 	if (ktriov != NULL) {
15741178Smarc 		if (error == 0)
15843448Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
15943448Smckusick 			    cnt, error);
16037728Smckusick 		FREE(ktriov, M_TEMP);
16137728Smckusick 	}
16237728Smckusick #endif
16342922Smckusick 	*retval = cnt;
16437127Skarels done:
16552481Storek 	if (needfree)
16652481Storek 		FREE(needfree, M_IOV);
16744405Skarels 	return (error);
1687423Sroot }
1697423Sroot 
1707423Sroot /*
1717423Sroot  * Write system call
1727423Sroot  */
17342922Smckusick write(p, uap, retval)
17442922Smckusick 	struct proc *p;
17542922Smckusick 	register struct args {
1767423Sroot 		int	fdes;
1777423Sroot 		char	*cbuf;
17826474Skarels 		unsigned count;
17942922Smckusick 	} *uap;
18042922Smckusick 	int *retval;
18142922Smckusick {
18237728Smckusick 	register struct file *fp;
18345914Smckusick 	register struct filedesc *fdp = p->p_fd;
1847820Sroot 	struct uio auio;
1857820Sroot 	struct iovec aiov;
18637728Smckusick 	long cnt, error = 0;
18737728Smckusick #ifdef KTRACE
18837728Smckusick 	struct iovec ktriov;
18937728Smckusick #endif
1907423Sroot 
19147540Skarels 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
19247974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
19337728Smckusick 	    (fp->f_flag & FWRITE) == 0)
19444405Skarels 		return (EBADF);
19537728Smckusick 	aiov.iov_base = (caddr_t)uap->cbuf;
19637728Smckusick 	aiov.iov_len = uap->count;
1977820Sroot 	auio.uio_iov = &aiov;
1987820Sroot 	auio.uio_iovcnt = 1;
19937728Smckusick 	auio.uio_resid = uap->count;
20037728Smckusick 	auio.uio_rw = UIO_WRITE;
20137728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
20248027Smckusick 	auio.uio_procp = p;
20337728Smckusick #ifdef KTRACE
20437728Smckusick 	/*
20537728Smckusick 	 * if tracing, save a copy of iovec
20637728Smckusick 	 */
20742922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
20837728Smckusick 		ktriov = aiov;
20937728Smckusick #endif
21037728Smckusick 	cnt = uap->count;
21140703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
21240703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
21340703Skarels 		    error == EINTR || error == EWOULDBLOCK))
21440703Skarels 			error = 0;
21540703Skarels 		if (error == EPIPE)
21642922Smckusick 			psignal(p, SIGPIPE);
21740703Skarels 	}
21837728Smckusick 	cnt -= auio.uio_resid;
21937728Smckusick #ifdef KTRACE
22042922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
22142922Smckusick 		ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
22243448Smckusick 		    &ktriov, cnt, error);
22337728Smckusick #endif
22442922Smckusick 	*retval = cnt;
22544405Skarels 	return (error);
2267820Sroot }
2277820Sroot 
22842922Smckusick /*
22942922Smckusick  * Gather write system call
23042922Smckusick  */
23142922Smckusick writev(p, uap, retval)
23242922Smckusick 	struct proc *p;
23342922Smckusick 	register struct args {
2347820Sroot 		int	fdes;
2357820Sroot 		struct	iovec *iovp;
23626474Skarels 		unsigned iovcnt;
23742922Smckusick 	} *uap;
23842922Smckusick 	int *retval;
23942922Smckusick {
24037728Smckusick 	register struct file *fp;
24145914Smckusick 	register struct filedesc *fdp = p->p_fd;
2427820Sroot 	struct uio auio;
24337728Smckusick 	register struct iovec *iov;
24452481Storek 	struct iovec *needfree;
24537728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
24637728Smckusick 	long i, cnt, error = 0;
24744939Skarels 	unsigned iovlen;
24837728Smckusick #ifdef KTRACE
24937728Smckusick 	struct iovec *ktriov = NULL;
25037728Smckusick #endif
2517820Sroot 
25247540Skarels 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
25347974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
25437728Smckusick 	    (fp->f_flag & FWRITE) == 0)
25544405Skarels 		return (EBADF);
25644939Skarels 	/* note: can't use iovlen until iovcnt is validated */
25744939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
25837127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
25937728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
26044405Skarels 			return (EINVAL);
26144939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
26252481Storek 		needfree = iov;
26352481Storek 	} else {
26437127Skarels 		iov = aiov;
26552481Storek 		needfree = NULL;
26652481Storek 	}
26737127Skarels 	auio.uio_iov = iov;
2687820Sroot 	auio.uio_iovcnt = uap->iovcnt;
26937728Smckusick 	auio.uio_rw = UIO_WRITE;
27037728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
27148027Smckusick 	auio.uio_procp = p;
27244939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
27337127Skarels 		goto done;
27437728Smckusick 	auio.uio_resid = 0;
27537728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
2767820Sroot 		if (iov->iov_len < 0) {
27737728Smckusick 			error = EINVAL;
27837728Smckusick 			goto done;
2797820Sroot 		}
28037728Smckusick 		auio.uio_resid += iov->iov_len;
28137728Smckusick 		if (auio.uio_resid < 0) {
28237728Smckusick 			error = EINVAL;
28337728Smckusick 			goto done;
2847820Sroot 		}
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)
30842922Smckusick 			ktrgenio(p->p_tracep, uap->fdes, 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  */
32342922Smckusick /* ARGSUSED */
32442922Smckusick ioctl(p, uap, retval)
32542922Smckusick 	struct proc *p;
32642922Smckusick 	register struct args {
3277423Sroot 		int	fdes;
3287423Sroot 		int	cmd;
3297423Sroot 		caddr_t	cmarg;
33042922Smckusick 	} *uap;
33142922Smckusick 	int *retval;
33242922Smckusick {
33342922Smckusick 	register struct file *fp;
33445914Smckusick 	register struct filedesc *fdp = p->p_fd;
33540703Skarels 	register int com, error;
3367820Sroot 	register u_int size;
33731653Smckusick 	caddr_t memp = 0;
33830530Skarels #define STK_PARAMS	128
33933480Skarels 	char stkbuf[STK_PARAMS];
34033480Skarels 	caddr_t data = stkbuf;
34148027Smckusick 	int tmp;
3427423Sroot 
34347540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
34447974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
34544405Skarels 		return (EBADF);
34640703Skarels 	if ((fp->f_flag & (FREAD|FWRITE)) == 0)
34744405Skarels 		return (EBADF);
3487624Ssam 	com = uap->cmd;
3497624Ssam 
3507624Ssam 	if (com == FIOCLEX) {
35147974Skarels 		fdp->fd_ofileflags[uap->fdes] |= UF_EXCLOSE;
35244405Skarels 		return (0);
3537423Sroot 	}
3547624Ssam 	if (com == FIONCLEX) {
35547974Skarels 		fdp->fd_ofileflags[uap->fdes] &= ~UF_EXCLOSE;
35644405Skarels 		return (0);
3577423Sroot 	}
3587624Ssam 
3597624Ssam 	/*
3607624Ssam 	 * Interpret high order word to find
3617624Ssam 	 * amount of data to be copied to/from the
3627624Ssam 	 * user's address space.
3637624Ssam 	 */
36430530Skarels 	size = IOCPARM_LEN(com);
36540703Skarels 	if (size > IOCPARM_MAX)
36644405Skarels 		return (ENOTTY);
36733480Skarels 	if (size > sizeof (stkbuf)) {
36843383Smckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
36931653Smckusick 		data = memp;
37030530Skarels 	}
37110601Ssam 	if (com&IOC_IN) {
37210601Ssam 		if (size) {
37340703Skarels 			error = copyin(uap->cmarg, data, (u_int)size);
37440703Skarels 			if (error) {
37531653Smckusick 				if (memp)
37631653Smckusick 					free(memp, M_IOCTLOPS);
37744405Skarels 				return (error);
37831653Smckusick 			}
37910601Ssam 		} else
38010601Ssam 			*(caddr_t *)data = uap->cmarg;
38110601Ssam 	} else if ((com&IOC_OUT) && size)
38210601Ssam 		/*
38337127Skarels 		 * Zero the buffer so the user always
38437127Skarels 		 * gets back something deterministic.
38510601Ssam 		 */
38630530Skarels 		bzero(data, size);
38711284Ssam 	else if (com&IOC_VOID)
38811284Ssam 		*(caddr_t *)data = uap->cmarg;
3897423Sroot 
39012751Ssam 	switch (com) {
3917624Ssam 
39212751Ssam 	case FIONBIO:
39348027Smckusick 		if (tmp = *(int *)data)
39449941Smckusick 			fp->f_flag |= FNONBLOCK;
39548027Smckusick 		else
39649941Smckusick 			fp->f_flag &= ~FNONBLOCK;
39748027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
39830530Skarels 		break;
39912751Ssam 
40012751Ssam 	case FIOASYNC:
40148027Smckusick 		if (tmp = *(int *)data)
40248027Smckusick 			fp->f_flag |= FASYNC;
40348027Smckusick 		else
40448027Smckusick 			fp->f_flag &= ~FASYNC;
40548027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
40630530Skarels 		break;
40712751Ssam 
40812751Ssam 	case FIOSETOWN:
40948027Smckusick 		tmp = *(int *)data;
41048027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
41148027Smckusick 			((struct socket *)fp->f_data)->so_pgid = tmp;
41248027Smckusick 			error = 0;
41348027Smckusick 			break;
41448027Smckusick 		}
41548027Smckusick 		if (tmp <= 0) {
41648027Smckusick 			tmp = -tmp;
41748027Smckusick 		} else {
41848027Smckusick 			struct proc *p1 = pfind(tmp);
41948027Smckusick 			if (p1 == 0) {
42048027Smckusick 				error = ESRCH;
42148027Smckusick 				break;
42248027Smckusick 			}
42348027Smckusick 			tmp = p1->p_pgrp->pg_id;
42448027Smckusick 		}
42548027Smckusick 		error = (*fp->f_ops->fo_ioctl)
42648027Smckusick 			(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
42730530Skarels 		break;
42812751Ssam 
42912751Ssam 	case FIOGETOWN:
43048027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
43148027Smckusick 			error = 0;
43248027Smckusick 			*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
43348027Smckusick 			break;
43448027Smckusick 		}
43548027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
43648027Smckusick 		*(int *)data = -*(int *)data;
43730530Skarels 		break;
43848027Smckusick 
43930530Skarels 	default:
44047540Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
44130530Skarels 		/*
44230530Skarels 		 * Copy any data to user, size was
44330530Skarels 		 * already set and checked above.
44430530Skarels 		 */
44540703Skarels 		if (error == 0 && (com&IOC_OUT) && size)
44640703Skarels 			error = copyout(data, uap->cmarg, (u_int)size);
44730530Skarels 		break;
4487423Sroot 	}
44931653Smckusick 	if (memp)
45031653Smckusick 		free(memp, M_IOCTLOPS);
45144405Skarels 	return (error);
4527423Sroot }
4537423Sroot 
45449227Skarels int	selwait, nselcoll;
45517593Skarels 
4567423Sroot /*
45712751Ssam  * Select system call.
4587423Sroot  */
45942922Smckusick select(p, uap, retval)
46042922Smckusick 	register struct proc *p;
46142922Smckusick 	register struct args {
46212751Ssam 		int	nd;
46323523Skarels 		fd_set	*in, *ou, *ex;
46412751Ssam 		struct	timeval *tv;
46542922Smckusick 	} *uap;
46642922Smckusick 	int *retval;
46742922Smckusick {
46823523Skarels 	fd_set ibits[3], obits[3];
46912751Ssam 	struct timeval atv;
47040703Skarels 	int s, ncoll, ni, error = 0, timo;
47112751Ssam 
47226277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
47326277Skarels 	bzero((caddr_t)obits, sizeof(obits));
47447540Skarels 	if (uap->nd > p->p_fd->fd_nfiles)
47547540Skarels 		uap->nd = p->p_fd->fd_nfiles;	/* forgiving; slightly wrong */
47623523Skarels 	ni = howmany(uap->nd, NFDBITS);
47712751Ssam 
47812751Ssam #define	getbits(name, x) \
47912751Ssam 	if (uap->name) { \
48040703Skarels 		error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
48126277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
48240703Skarels 		if (error) \
48312751Ssam 			goto done; \
48417593Skarels 	}
48512751Ssam 	getbits(in, 0);
48612751Ssam 	getbits(ou, 1);
48712751Ssam 	getbits(ex, 2);
48812751Ssam #undef	getbits
48912751Ssam 
49012751Ssam 	if (uap->tv) {
49140703Skarels 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
49212751Ssam 			sizeof (atv));
49340703Skarels 		if (error)
49412751Ssam 			goto done;
49512751Ssam 		if (itimerfix(&atv)) {
49640703Skarels 			error = EINVAL;
49712751Ssam 			goto done;
49812751Ssam 		}
49917934Skarels 		s = splhigh(); timevaladd(&atv, &time); splx(s);
50040703Skarels 		timo = hzto(&atv);
50140703Skarels 	} else
50240703Skarels 		timo = 0;
50312751Ssam retry:
50412751Ssam 	ncoll = nselcoll;
50542922Smckusick 	p->p_flag |= SSEL;
50647540Skarels 	error = selscan(p, ibits, obits, uap->nd, retval);
50742922Smckusick 	if (error || *retval)
50812751Ssam 		goto done;
50917934Skarels 	s = splhigh();
51012971Ssam 	/* this should be timercmp(&time, &atv, >=) */
51112971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
51212971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
51312751Ssam 		splx(s);
51412751Ssam 		goto done;
51512751Ssam 	}
51642922Smckusick 	if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
51712751Ssam 		splx(s);
51812751Ssam 		goto retry;
51912751Ssam 	}
52042922Smckusick 	p->p_flag &= ~SSEL;
52140703Skarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
52212751Ssam 	splx(s);
52340703Skarels 	if (error == 0)
52440703Skarels 		goto retry;
52512751Ssam done:
52642922Smckusick 	p->p_flag &= ~SSEL;
52740703Skarels 	/* select is not restarted after signals... */
52840703Skarels 	if (error == ERESTART)
52940703Skarels 		error = EINTR;
53040703Skarels 	if (error == EWOULDBLOCK)
53140703Skarels 		error = 0;
53212751Ssam #define	putbits(name, x) \
53312751Ssam 	if (uap->name) { \
53440703Skarels 		int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
53526277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
53640703Skarels 		if (error2) \
53740703Skarels 			error = error2; \
53812751Ssam 	}
53940703Skarels 	if (error == 0) {
54021106Skarels 		putbits(in, 0);
54121106Skarels 		putbits(ou, 1);
54221106Skarels 		putbits(ex, 2);
54312751Ssam #undef putbits
54421106Skarels 	}
54544405Skarels 	return (error);
54612751Ssam }
54712751Ssam 
54847540Skarels selscan(p, ibits, obits, nfd, retval)
54947540Skarels 	struct proc *p;
55023523Skarels 	fd_set *ibits, *obits;
55142922Smckusick 	int nfd, *retval;
55212751Ssam {
55347540Skarels 	register struct filedesc *fdp = p->p_fd;
55452481Storek 	register int msk, i, j, fd;
55523523Skarels 	register fd_mask bits;
55612751Ssam 	struct file *fp;
55752481Storek 	int n = 0;
55852481Storek 	static int flag[3] = { FREAD, FWRITE, 0 };
55912751Ssam 
56052481Storek 	for (msk = 0; msk < 3; msk++) {
56123523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
56252481Storek 			bits = ibits[msk].fds_bits[i/NFDBITS];
56352481Storek 			while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
56417593Skarels 				bits &= ~(1 << j);
56552481Storek 				fp = fdp->fd_ofiles[fd];
56652481Storek 				if (fp == NULL)
56752481Storek 					return (EBADF);
56852481Storek 				if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
56952481Storek 					FD_SET(fd, &obits[msk]);
57017593Skarels 					n++;
57117593Skarels 				}
57212751Ssam 			}
57312751Ssam 		}
57412751Ssam 	}
57542922Smckusick 	*retval = n;
57652481Storek 	return (0);
57712751Ssam }
57812751Ssam 
5797423Sroot /*ARGSUSED*/
58047974Skarels #ifdef __STDC__
58147974Skarels seltrue(dev_t dev, int which, struct proc *p)
58247974Skarels #else
58347540Skarels seltrue(dev, flag, p)
58412751Ssam 	dev_t dev;
58512751Ssam 	int flag;
58647540Skarels 	struct proc *p;
58747974Skarels #endif
5887423Sroot {
5897423Sroot 
59012751Ssam 	return (1);
5917423Sroot }
5928103Sroot 
593*52525Smckusick /*
594*52525Smckusick  * Record a select request.
595*52525Smckusick  */
596*52525Smckusick void
597*52525Smckusick selrecord(selector, sip)
598*52525Smckusick 	struct proc *selector;
599*52525Smckusick 	struct selinfo *sip;
6008103Sroot {
601*52525Smckusick 	struct proc *p;
602*52525Smckusick 	pid_t mypid;
6038103Sroot 
604*52525Smckusick 	mypid = selector->p_pid;
605*52525Smckusick 	if (sip->si_pid == mypid)
606*52525Smckusick 		return;
607*52525Smckusick 	if (sip->si_pid && (p = pfind(sip->si_pid)) &&
608*52525Smckusick 	    p->p_wchan == (caddr_t)&selwait)
609*52525Smckusick 		sip->si_flags |= SI_COLL;
610*52525Smckusick 	else
611*52525Smckusick 		sip->si_pid = mypid;
612*52525Smckusick }
613*52525Smckusick 
614*52525Smckusick /*
615*52525Smckusick  * Do a wakeup when a selectable event occurs.
616*52525Smckusick  */
617*52525Smckusick void
618*52525Smckusick selwakeup(sip)
619*52525Smckusick 	register struct selinfo *sip;
620*52525Smckusick {
621*52525Smckusick 	register struct proc *p;
622*52525Smckusick 	int s;
623*52525Smckusick 
624*52525Smckusick 	if (sip->si_pid == 0)
625*52525Smckusick 		return;
626*52525Smckusick 	if (sip->si_flags & SI_COLL) {
62712751Ssam 		nselcoll++;
628*52525Smckusick 		sip->si_flags &= ~SI_COLL;
62912751Ssam 		wakeup((caddr_t)&selwait);
63012751Ssam 	}
631*52525Smckusick 	if ((p = pfind(sip->si_pid)) == 0) {
632*52525Smckusick 		sip->si_pid = 0;
633*52525Smckusick 	} else {
634*52525Smckusick 		s = splhigh();
63517270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
63617270Skarels 			if (p->p_stat == SSLEEP)
63717270Skarels 				setrun(p);
63817270Skarels 			else
63917270Skarels 				unsleep(p);
64017270Skarels 		} else if (p->p_flag & SSEL)
64112751Ssam 			p->p_flag &= ~SSEL;
64212751Ssam 		splx(s);
64312751Ssam 	}
6448103Sroot }
645