xref: /csrg-svn/sys/kern/sys_generic.c (revision 49941)
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*49941Smckusick  *	@(#)sys_generic.c	7.30 (Berkeley) 05/30/91
823384Smckusick  */
97423Sroot 
1017094Sbloom #include "param.h"
1117094Sbloom #include "systm.h"
1245914Smckusick #include "filedesc.h"
1317094Sbloom #include "ioctl.h"
1417094Sbloom #include "file.h"
1548027Smckusick #include "socketvar.h"
1617094Sbloom #include "proc.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;
9744939Skarels 	struct iovec *saveiov;
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);
11544939Skarels 		saveiov = iov;
11637127Skarels 	} else
11737127Skarels 		iov = aiov;
11837127Skarels 	auio.uio_iov = iov;
1197820Sroot 	auio.uio_iovcnt = uap->iovcnt;
12037728Smckusick 	auio.uio_rw = UIO_READ;
12137728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
12248027Smckusick 	auio.uio_procp = p;
12344939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
12437127Skarels 		goto done;
12537728Smckusick 	auio.uio_resid = 0;
12637728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
12737728Smckusick 		if (iov->iov_len < 0) {
12837728Smckusick 			error = EINVAL;
12937728Smckusick 			goto done;
13037728Smckusick 		}
13137728Smckusick 		auio.uio_resid += iov->iov_len;
13237728Smckusick 		if (auio.uio_resid < 0) {
13337728Smckusick 			error = EINVAL;
13437728Smckusick 			goto done;
13537728Smckusick 		}
13637728Smckusick 		iov++;
13737728Smckusick 	}
13837728Smckusick #ifdef KTRACE
13937728Smckusick 	/*
14037728Smckusick 	 * if tracing, save a copy of iovec
14137728Smckusick 	 */
14242922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
14337728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
14437728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
14537728Smckusick 	}
14637728Smckusick #endif
14737728Smckusick 	cnt = auio.uio_resid;
14840703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
14940703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
15040703Skarels 		    error == EINTR || error == EWOULDBLOCK))
15140703Skarels 			error = 0;
15237728Smckusick 	cnt -= auio.uio_resid;
15337728Smckusick #ifdef KTRACE
15437728Smckusick 	if (ktriov != NULL) {
15541178Smarc 		if (error == 0)
15643448Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
15743448Smckusick 			    cnt, error);
15837728Smckusick 		FREE(ktriov, M_TEMP);
15937728Smckusick 	}
16037728Smckusick #endif
16142922Smckusick 	*retval = cnt;
16237127Skarels done:
16337728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
16444939Skarels 		FREE(saveiov, M_IOV);
16544405Skarels 	return (error);
1667423Sroot }
1677423Sroot 
1687423Sroot /*
1697423Sroot  * Write system call
1707423Sroot  */
17142922Smckusick write(p, uap, retval)
17242922Smckusick 	struct proc *p;
17342922Smckusick 	register struct args {
1747423Sroot 		int	fdes;
1757423Sroot 		char	*cbuf;
17626474Skarels 		unsigned count;
17742922Smckusick 	} *uap;
17842922Smckusick 	int *retval;
17942922Smckusick {
18037728Smckusick 	register struct file *fp;
18145914Smckusick 	register struct filedesc *fdp = p->p_fd;
1827820Sroot 	struct uio auio;
1837820Sroot 	struct iovec aiov;
18437728Smckusick 	long cnt, error = 0;
18537728Smckusick #ifdef KTRACE
18637728Smckusick 	struct iovec ktriov;
18737728Smckusick #endif
1887423Sroot 
18947540Skarels 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
19047974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
19137728Smckusick 	    (fp->f_flag & FWRITE) == 0)
19244405Skarels 		return (EBADF);
19337728Smckusick 	aiov.iov_base = (caddr_t)uap->cbuf;
19437728Smckusick 	aiov.iov_len = uap->count;
1957820Sroot 	auio.uio_iov = &aiov;
1967820Sroot 	auio.uio_iovcnt = 1;
19737728Smckusick 	auio.uio_resid = uap->count;
19837728Smckusick 	auio.uio_rw = UIO_WRITE;
19937728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
20048027Smckusick 	auio.uio_procp = p;
20137728Smckusick #ifdef KTRACE
20237728Smckusick 	/*
20337728Smckusick 	 * if tracing, save a copy of iovec
20437728Smckusick 	 */
20542922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
20637728Smckusick 		ktriov = aiov;
20737728Smckusick #endif
20837728Smckusick 	cnt = uap->count;
20940703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
21040703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
21140703Skarels 		    error == EINTR || error == EWOULDBLOCK))
21240703Skarels 			error = 0;
21340703Skarels 		if (error == EPIPE)
21442922Smckusick 			psignal(p, SIGPIPE);
21540703Skarels 	}
21637728Smckusick 	cnt -= auio.uio_resid;
21737728Smckusick #ifdef KTRACE
21842922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
21942922Smckusick 		ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
22043448Smckusick 		    &ktriov, cnt, error);
22137728Smckusick #endif
22242922Smckusick 	*retval = cnt;
22344405Skarels 	return (error);
2247820Sroot }
2257820Sroot 
22642922Smckusick /*
22742922Smckusick  * Gather write system call
22842922Smckusick  */
22942922Smckusick writev(p, uap, retval)
23042922Smckusick 	struct proc *p;
23142922Smckusick 	register struct args {
2327820Sroot 		int	fdes;
2337820Sroot 		struct	iovec *iovp;
23426474Skarels 		unsigned iovcnt;
23542922Smckusick 	} *uap;
23642922Smckusick 	int *retval;
23742922Smckusick {
23837728Smckusick 	register struct file *fp;
23945914Smckusick 	register struct filedesc *fdp = p->p_fd;
2407820Sroot 	struct uio auio;
24137728Smckusick 	register struct iovec *iov;
24244939Skarels 	struct iovec *saveiov;
24337728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
24437728Smckusick 	long i, cnt, error = 0;
24544939Skarels 	unsigned iovlen;
24637728Smckusick #ifdef KTRACE
24737728Smckusick 	struct iovec *ktriov = NULL;
24837728Smckusick #endif
2497820Sroot 
25047540Skarels 	if (((unsigned)uap->fdes) >= fdp->fd_nfiles ||
25147974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL ||
25237728Smckusick 	    (fp->f_flag & FWRITE) == 0)
25344405Skarels 		return (EBADF);
25444939Skarels 	/* note: can't use iovlen until iovcnt is validated */
25544939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
25637127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
25737728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
25844405Skarels 			return (EINVAL);
25944939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
26044939Skarels 		saveiov = iov;
26137127Skarels 	} else
26237127Skarels 		iov = aiov;
26337127Skarels 	auio.uio_iov = iov;
2647820Sroot 	auio.uio_iovcnt = uap->iovcnt;
26537728Smckusick 	auio.uio_rw = UIO_WRITE;
26637728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
26748027Smckusick 	auio.uio_procp = p;
26844939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
26937127Skarels 		goto done;
27037728Smckusick 	auio.uio_resid = 0;
27137728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
2727820Sroot 		if (iov->iov_len < 0) {
27337728Smckusick 			error = EINVAL;
27437728Smckusick 			goto done;
2757820Sroot 		}
27637728Smckusick 		auio.uio_resid += iov->iov_len;
27737728Smckusick 		if (auio.uio_resid < 0) {
27837728Smckusick 			error = EINVAL;
27937728Smckusick 			goto done;
2807820Sroot 		}
28113270Ssam 		iov++;
2827820Sroot 	}
28337127Skarels #ifdef KTRACE
28437728Smckusick 	/*
28537728Smckusick 	 * if tracing, save a copy of iovec
28637728Smckusick 	 */
28742922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
28837127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
28937728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
29037127Skarels 	}
29137127Skarels #endif
29237728Smckusick 	cnt = auio.uio_resid;
29340703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
29440703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
29540703Skarels 		    error == EINTR || error == EWOULDBLOCK))
29640703Skarels 			error = 0;
29740703Skarels 		if (error == EPIPE)
29842922Smckusick 			psignal(p, SIGPIPE);
29940703Skarels 	}
30037728Smckusick 	cnt -= auio.uio_resid;
30137127Skarels #ifdef KTRACE
30237127Skarels 	if (ktriov != NULL) {
30341178Smarc 		if (error == 0)
30442922Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
30543448Smckusick 				ktriov, cnt, error);
30637127Skarels 		FREE(ktriov, M_TEMP);
30737127Skarels 	}
30837127Skarels #endif
30942922Smckusick 	*retval = cnt;
31037728Smckusick done:
31137728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
31244939Skarels 		FREE(saveiov, M_IOV);
31344405Skarels 	return (error);
3147423Sroot }
3157423Sroot 
3167423Sroot /*
3177423Sroot  * Ioctl system call
3187423Sroot  */
31942922Smckusick /* ARGSUSED */
32042922Smckusick ioctl(p, uap, retval)
32142922Smckusick 	struct proc *p;
32242922Smckusick 	register struct args {
3237423Sroot 		int	fdes;
3247423Sroot 		int	cmd;
3257423Sroot 		caddr_t	cmarg;
32642922Smckusick 	} *uap;
32742922Smckusick 	int *retval;
32842922Smckusick {
32942922Smckusick 	register struct file *fp;
33045914Smckusick 	register struct filedesc *fdp = p->p_fd;
33140703Skarels 	register int com, error;
3327820Sroot 	register u_int size;
33331653Smckusick 	caddr_t memp = 0;
33430530Skarels #define STK_PARAMS	128
33533480Skarels 	char stkbuf[STK_PARAMS];
33633480Skarels 	caddr_t data = stkbuf;
33748027Smckusick 	int tmp;
3387423Sroot 
33947540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
34047974Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
34144405Skarels 		return (EBADF);
34240703Skarels 	if ((fp->f_flag & (FREAD|FWRITE)) == 0)
34344405Skarels 		return (EBADF);
3447624Ssam 	com = uap->cmd;
3457624Ssam 
3467624Ssam 	if (com == FIOCLEX) {
34747974Skarels 		fdp->fd_ofileflags[uap->fdes] |= UF_EXCLOSE;
34844405Skarels 		return (0);
3497423Sroot 	}
3507624Ssam 	if (com == FIONCLEX) {
35147974Skarels 		fdp->fd_ofileflags[uap->fdes] &= ~UF_EXCLOSE;
35244405Skarels 		return (0);
3537423Sroot 	}
3547624Ssam 
3557624Ssam 	/*
3567624Ssam 	 * Interpret high order word to find
3577624Ssam 	 * amount of data to be copied to/from the
3587624Ssam 	 * user's address space.
3597624Ssam 	 */
36030530Skarels 	size = IOCPARM_LEN(com);
36140703Skarels 	if (size > IOCPARM_MAX)
36244405Skarels 		return (ENOTTY);
36333480Skarels 	if (size > sizeof (stkbuf)) {
36443383Smckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
36531653Smckusick 		data = memp;
36630530Skarels 	}
36710601Ssam 	if (com&IOC_IN) {
36810601Ssam 		if (size) {
36940703Skarels 			error = copyin(uap->cmarg, data, (u_int)size);
37040703Skarels 			if (error) {
37131653Smckusick 				if (memp)
37231653Smckusick 					free(memp, M_IOCTLOPS);
37344405Skarels 				return (error);
37431653Smckusick 			}
37510601Ssam 		} else
37610601Ssam 			*(caddr_t *)data = uap->cmarg;
37710601Ssam 	} else if ((com&IOC_OUT) && size)
37810601Ssam 		/*
37937127Skarels 		 * Zero the buffer so the user always
38037127Skarels 		 * gets back something deterministic.
38110601Ssam 		 */
38230530Skarels 		bzero(data, size);
38311284Ssam 	else if (com&IOC_VOID)
38411284Ssam 		*(caddr_t *)data = uap->cmarg;
3857423Sroot 
38612751Ssam 	switch (com) {
3877624Ssam 
38812751Ssam 	case FIONBIO:
38948027Smckusick 		if (tmp = *(int *)data)
390*49941Smckusick 			fp->f_flag |= FNONBLOCK;
39148027Smckusick 		else
392*49941Smckusick 			fp->f_flag &= ~FNONBLOCK;
39348027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
39430530Skarels 		break;
39512751Ssam 
39612751Ssam 	case FIOASYNC:
39748027Smckusick 		if (tmp = *(int *)data)
39848027Smckusick 			fp->f_flag |= FASYNC;
39948027Smckusick 		else
40048027Smckusick 			fp->f_flag &= ~FASYNC;
40148027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
40230530Skarels 		break;
40312751Ssam 
40412751Ssam 	case FIOSETOWN:
40548027Smckusick 		tmp = *(int *)data;
40648027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
40748027Smckusick 			((struct socket *)fp->f_data)->so_pgid = tmp;
40848027Smckusick 			error = 0;
40948027Smckusick 			break;
41048027Smckusick 		}
41148027Smckusick 		if (tmp <= 0) {
41248027Smckusick 			tmp = -tmp;
41348027Smckusick 		} else {
41448027Smckusick 			struct proc *p1 = pfind(tmp);
41548027Smckusick 			if (p1 == 0) {
41648027Smckusick 				error = ESRCH;
41748027Smckusick 				break;
41848027Smckusick 			}
41948027Smckusick 			tmp = p1->p_pgrp->pg_id;
42048027Smckusick 		}
42148027Smckusick 		error = (*fp->f_ops->fo_ioctl)
42248027Smckusick 			(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p);
42330530Skarels 		break;
42412751Ssam 
42512751Ssam 	case FIOGETOWN:
42648027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
42748027Smckusick 			error = 0;
42848027Smckusick 			*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
42948027Smckusick 			break;
43048027Smckusick 		}
43148027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, (int)TIOCGPGRP, data, p);
43248027Smckusick 		*(int *)data = -*(int *)data;
43330530Skarels 		break;
43448027Smckusick 
43530530Skarels 	default:
43647540Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
43730530Skarels 		/*
43830530Skarels 		 * Copy any data to user, size was
43930530Skarels 		 * already set and checked above.
44030530Skarels 		 */
44140703Skarels 		if (error == 0 && (com&IOC_OUT) && size)
44240703Skarels 			error = copyout(data, uap->cmarg, (u_int)size);
44330530Skarels 		break;
4447423Sroot 	}
44531653Smckusick 	if (memp)
44631653Smckusick 		free(memp, M_IOCTLOPS);
44744405Skarels 	return (error);
4487423Sroot }
4497423Sroot 
45049227Skarels int	selwait, nselcoll;
45117593Skarels 
4527423Sroot /*
45312751Ssam  * Select system call.
4547423Sroot  */
45542922Smckusick select(p, uap, retval)
45642922Smckusick 	register struct proc *p;
45742922Smckusick 	register struct args {
45812751Ssam 		int	nd;
45923523Skarels 		fd_set	*in, *ou, *ex;
46012751Ssam 		struct	timeval *tv;
46142922Smckusick 	} *uap;
46242922Smckusick 	int *retval;
46342922Smckusick {
46423523Skarels 	fd_set ibits[3], obits[3];
46512751Ssam 	struct timeval atv;
46640703Skarels 	int s, ncoll, ni, error = 0, timo;
46712751Ssam 
46826277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
46926277Skarels 	bzero((caddr_t)obits, sizeof(obits));
47047540Skarels 	if (uap->nd > p->p_fd->fd_nfiles)
47147540Skarels 		uap->nd = p->p_fd->fd_nfiles;	/* forgiving; slightly wrong */
47223523Skarels 	ni = howmany(uap->nd, NFDBITS);
47312751Ssam 
47412751Ssam #define	getbits(name, x) \
47512751Ssam 	if (uap->name) { \
47640703Skarels 		error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
47726277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
47840703Skarels 		if (error) \
47912751Ssam 			goto done; \
48017593Skarels 	}
48112751Ssam 	getbits(in, 0);
48212751Ssam 	getbits(ou, 1);
48312751Ssam 	getbits(ex, 2);
48412751Ssam #undef	getbits
48512751Ssam 
48612751Ssam 	if (uap->tv) {
48740703Skarels 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
48812751Ssam 			sizeof (atv));
48940703Skarels 		if (error)
49012751Ssam 			goto done;
49112751Ssam 		if (itimerfix(&atv)) {
49240703Skarels 			error = EINVAL;
49312751Ssam 			goto done;
49412751Ssam 		}
49517934Skarels 		s = splhigh(); timevaladd(&atv, &time); splx(s);
49640703Skarels 		timo = hzto(&atv);
49740703Skarels 	} else
49840703Skarels 		timo = 0;
49912751Ssam retry:
50012751Ssam 	ncoll = nselcoll;
50142922Smckusick 	p->p_flag |= SSEL;
50247540Skarels 	error = selscan(p, ibits, obits, uap->nd, retval);
50342922Smckusick 	if (error || *retval)
50412751Ssam 		goto done;
50517934Skarels 	s = splhigh();
50612971Ssam 	/* this should be timercmp(&time, &atv, >=) */
50712971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
50812971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
50912751Ssam 		splx(s);
51012751Ssam 		goto done;
51112751Ssam 	}
51242922Smckusick 	if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
51312751Ssam 		splx(s);
51412751Ssam 		goto retry;
51512751Ssam 	}
51642922Smckusick 	p->p_flag &= ~SSEL;
51740703Skarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
51812751Ssam 	splx(s);
51940703Skarels 	if (error == 0)
52040703Skarels 		goto retry;
52112751Ssam done:
52242922Smckusick 	p->p_flag &= ~SSEL;
52340703Skarels 	/* select is not restarted after signals... */
52440703Skarels 	if (error == ERESTART)
52540703Skarels 		error = EINTR;
52640703Skarels 	if (error == EWOULDBLOCK)
52740703Skarels 		error = 0;
52812751Ssam #define	putbits(name, x) \
52912751Ssam 	if (uap->name) { \
53040703Skarels 		int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
53126277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
53240703Skarels 		if (error2) \
53340703Skarels 			error = error2; \
53412751Ssam 	}
53540703Skarels 	if (error == 0) {
53621106Skarels 		putbits(in, 0);
53721106Skarels 		putbits(ou, 1);
53821106Skarels 		putbits(ex, 2);
53912751Ssam #undef putbits
54021106Skarels 	}
54144405Skarels 	return (error);
54212751Ssam }
54312751Ssam 
54447540Skarels selscan(p, ibits, obits, nfd, retval)
54547540Skarels 	struct proc *p;
54623523Skarels 	fd_set *ibits, *obits;
54742922Smckusick 	int nfd, *retval;
54812751Ssam {
54947540Skarels 	register struct filedesc *fdp = p->p_fd;
55023523Skarels 	register int which, i, j;
55123523Skarels 	register fd_mask bits;
55212751Ssam 	int flag;
55312751Ssam 	struct file *fp;
55442922Smckusick 	int error = 0, n = 0;
55512751Ssam 
55612751Ssam 	for (which = 0; which < 3; which++) {
55712751Ssam 		switch (which) {
55812751Ssam 
55912751Ssam 		case 0:
56012751Ssam 			flag = FREAD; break;
56112751Ssam 
56212751Ssam 		case 1:
56312751Ssam 			flag = FWRITE; break;
56412751Ssam 
56512751Ssam 		case 2:
56612751Ssam 			flag = 0; break;
56712751Ssam 		}
56823523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
56923523Skarels 			bits = ibits[which].fds_bits[i/NFDBITS];
57017593Skarels 			while ((j = ffs(bits)) && i + --j < nfd) {
57117593Skarels 				bits &= ~(1 << j);
57247974Skarels 				fp = fdp->fd_ofiles[i + j];
57317593Skarels 				if (fp == NULL) {
57442922Smckusick 					error = EBADF;
57517593Skarels 					break;
57617593Skarels 				}
57747540Skarels 				if ((*fp->f_ops->fo_select)(fp, flag, p)) {
57823523Skarels 					FD_SET(i + j, &obits[which]);
57917593Skarels 					n++;
58017593Skarels 				}
58112751Ssam 			}
58212751Ssam 		}
58312751Ssam 	}
58442922Smckusick 	*retval = n;
58542922Smckusick 	return (error);
58612751Ssam }
58712751Ssam 
5887423Sroot /*ARGSUSED*/
58947974Skarels #ifdef __STDC__
59047974Skarels seltrue(dev_t dev, int which, struct proc *p)
59147974Skarels #else
59247540Skarels seltrue(dev, flag, p)
59312751Ssam 	dev_t dev;
59412751Ssam 	int flag;
59547540Skarels 	struct proc *p;
59647974Skarels #endif
5977423Sroot {
5987423Sroot 
59912751Ssam 	return (1);
6007423Sroot }
6018103Sroot 
60212751Ssam selwakeup(p, coll)
60312751Ssam 	register struct proc *p;
60412751Ssam 	int coll;
6058103Sroot {
6068103Sroot 
60712751Ssam 	if (coll) {
60812751Ssam 		nselcoll++;
60912751Ssam 		wakeup((caddr_t)&selwait);
61012751Ssam 	}
61112751Ssam 	if (p) {
61217934Skarels 		int s = splhigh();
61317270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
61417270Skarels 			if (p->p_stat == SSLEEP)
61517270Skarels 				setrun(p);
61617270Skarels 			else
61717270Skarels 				unsleep(p);
61817270Skarels 		} else if (p->p_flag & SSEL)
61912751Ssam 			p->p_flag &= ~SSEL;
62012751Ssam 		splx(s);
62112751Ssam 	}
6228103Sroot }
623