xref: /csrg-svn/sys/kern/sys_generic.c (revision 45122)
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*45122Sbostic  *	@(#)sys_generic.c	7.24 (Berkeley) 08/24/90
823384Smckusick  */
97423Sroot 
1017094Sbloom #include "param.h"
1117094Sbloom #include "systm.h"
1244405Skarels #include "user.h"
1317094Sbloom #include "ioctl.h"
1417094Sbloom #include "file.h"
1517094Sbloom #include "proc.h"
1617094Sbloom #include "uio.h"
1717094Sbloom #include "kernel.h"
1817094Sbloom #include "stat.h"
1931653Smckusick #include "malloc.h"
2037127Skarels #ifdef KTRACE
2137127Skarels #include "ktrace.h"
2237127Skarels #endif
237423Sroot 
247423Sroot /*
257423Sroot  * Read system call.
267423Sroot  */
27*45122Sbostic /* ARGSUSED */
2842922Smckusick read(p, uap, retval)
2942922Smckusick 	struct proc *p;
3042922Smckusick 	register struct args {
317423Sroot 		int	fdes;
327423Sroot 		char	*cbuf;
337423Sroot 		unsigned count;
3442922Smckusick 	} *uap;
3542922Smckusick 	int *retval;
3642922Smckusick {
3737728Smckusick 	register struct file *fp;
387746Sroot 	struct uio auio;
397746Sroot 	struct iovec aiov;
4037728Smckusick 	long cnt, error = 0;
4137728Smckusick #ifdef KTRACE
4237728Smckusick 	struct iovec ktriov;
4337728Smckusick #endif
447423Sroot 
4537728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
4637728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
4737728Smckusick 	    (fp->f_flag & FREAD) == 0)
4844405Skarels 		return (EBADF);
497820Sroot 	aiov.iov_base = (caddr_t)uap->cbuf;
507820Sroot 	aiov.iov_len = uap->count;
517820Sroot 	auio.uio_iov = &aiov;
527820Sroot 	auio.uio_iovcnt = 1;
5337728Smckusick 	auio.uio_resid = uap->count;
5437728Smckusick 	auio.uio_rw = UIO_READ;
5537728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
5637728Smckusick #ifdef KTRACE
5737728Smckusick 	/*
5837728Smckusick 	 * if tracing, save a copy of iovec
5937728Smckusick 	 */
6042922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
6137728Smckusick 		ktriov = aiov;
6237728Smckusick #endif
6337728Smckusick 	cnt = uap->count;
6440703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
6540703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
6640703Skarels 		    error == EINTR || error == EWOULDBLOCK))
6740703Skarels 			error = 0;
6837728Smckusick 	cnt -= auio.uio_resid;
6937728Smckusick #ifdef KTRACE
7042922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
7143448Smckusick 		ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
7237728Smckusick #endif
7342922Smckusick 	*retval = cnt;
7444405Skarels 	return (error);
757820Sroot }
767820Sroot 
7742922Smckusick /*
7842922Smckusick  * Scatter read system call.
7942922Smckusick  */
80*45122Sbostic /* ARGSUSED */
8142922Smckusick readv(p, uap, retval)
8242922Smckusick 	struct proc *p;
8342922Smckusick 	register struct args {
847820Sroot 		int	fdes;
857820Sroot 		struct	iovec *iovp;
8626474Skarels 		unsigned iovcnt;
8742922Smckusick 	} *uap;
8842922Smckusick 	int *retval;
8942922Smckusick {
9037728Smckusick 	register struct file *fp;
917820Sroot 	struct uio auio;
9237728Smckusick 	register struct iovec *iov;
9344939Skarels 	struct iovec *saveiov;
9437728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
9537728Smckusick 	long i, cnt, error = 0;
9644939Skarels 	unsigned iovlen;
9737728Smckusick #ifdef KTRACE
9837728Smckusick 	struct iovec *ktriov = NULL;
9937728Smckusick #endif
1007820Sroot 
10137728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
10237728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
10337728Smckusick 	    (fp->f_flag & FREAD) == 0)
10444405Skarels 		return (EBADF);
10544939Skarels 	/* note: can't use iovlen until iovcnt is validated */
10644939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
10737127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
10837728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
10944405Skarels 			return (EINVAL);
11044939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
11144939Skarels 		saveiov = iov;
11237127Skarels 	} else
11337127Skarels 		iov = aiov;
11437127Skarels 	auio.uio_iov = iov;
1157820Sroot 	auio.uio_iovcnt = uap->iovcnt;
11637728Smckusick 	auio.uio_rw = UIO_READ;
11737728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
11844939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
11937127Skarels 		goto done;
12037728Smckusick 	auio.uio_resid = 0;
12137728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
12237728Smckusick 		if (iov->iov_len < 0) {
12337728Smckusick 			error = EINVAL;
12437728Smckusick 			goto done;
12537728Smckusick 		}
12637728Smckusick 		auio.uio_resid += iov->iov_len;
12737728Smckusick 		if (auio.uio_resid < 0) {
12837728Smckusick 			error = EINVAL;
12937728Smckusick 			goto done;
13037728Smckusick 		}
13137728Smckusick 		iov++;
13237728Smckusick 	}
13337728Smckusick #ifdef KTRACE
13437728Smckusick 	/*
13537728Smckusick 	 * if tracing, save a copy of iovec
13637728Smckusick 	 */
13742922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
13837728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
13937728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
14037728Smckusick 	}
14137728Smckusick #endif
14237728Smckusick 	cnt = auio.uio_resid;
14340703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
14440703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
14540703Skarels 		    error == EINTR || error == EWOULDBLOCK))
14640703Skarels 			error = 0;
14737728Smckusick 	cnt -= auio.uio_resid;
14837728Smckusick #ifdef KTRACE
14937728Smckusick 	if (ktriov != NULL) {
15041178Smarc 		if (error == 0)
15143448Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
15243448Smckusick 			    cnt, error);
15337728Smckusick 		FREE(ktriov, M_TEMP);
15437728Smckusick 	}
15537728Smckusick #endif
15642922Smckusick 	*retval = cnt;
15737127Skarels done:
15837728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
15944939Skarels 		FREE(saveiov, M_IOV);
16044405Skarels 	return (error);
1617423Sroot }
1627423Sroot 
1637423Sroot /*
1647423Sroot  * Write system call
1657423Sroot  */
16642922Smckusick write(p, uap, retval)
16742922Smckusick 	struct proc *p;
16842922Smckusick 	register struct args {
1697423Sroot 		int	fdes;
1707423Sroot 		char	*cbuf;
17126474Skarels 		unsigned count;
17242922Smckusick 	} *uap;
17342922Smckusick 	int *retval;
17442922Smckusick {
17537728Smckusick 	register struct file *fp;
1767820Sroot 	struct uio auio;
1777820Sroot 	struct iovec aiov;
17837728Smckusick 	long cnt, error = 0;
17937728Smckusick #ifdef KTRACE
18037728Smckusick 	struct iovec ktriov;
18137728Smckusick #endif
1827423Sroot 
18337728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
18437728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
18537728Smckusick 	    (fp->f_flag & FWRITE) == 0)
18644405Skarels 		return (EBADF);
18737728Smckusick 	aiov.iov_base = (caddr_t)uap->cbuf;
18837728Smckusick 	aiov.iov_len = uap->count;
1897820Sroot 	auio.uio_iov = &aiov;
1907820Sroot 	auio.uio_iovcnt = 1;
19137728Smckusick 	auio.uio_resid = uap->count;
19237728Smckusick 	auio.uio_rw = UIO_WRITE;
19337728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
19437728Smckusick #ifdef KTRACE
19537728Smckusick 	/*
19637728Smckusick 	 * if tracing, save a copy of iovec
19737728Smckusick 	 */
19842922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
19937728Smckusick 		ktriov = aiov;
20037728Smckusick #endif
20137728Smckusick 	cnt = uap->count;
20240703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
20340703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
20440703Skarels 		    error == EINTR || error == EWOULDBLOCK))
20540703Skarels 			error = 0;
20640703Skarels 		if (error == EPIPE)
20742922Smckusick 			psignal(p, SIGPIPE);
20840703Skarels 	}
20937728Smckusick 	cnt -= auio.uio_resid;
21037728Smckusick #ifdef KTRACE
21142922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
21242922Smckusick 		ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
21343448Smckusick 		    &ktriov, cnt, error);
21437728Smckusick #endif
21542922Smckusick 	*retval = cnt;
21644405Skarels 	return (error);
2177820Sroot }
2187820Sroot 
21942922Smckusick /*
22042922Smckusick  * Gather write system call
22142922Smckusick  */
22242922Smckusick writev(p, uap, retval)
22342922Smckusick 	struct proc *p;
22442922Smckusick 	register struct args {
2257820Sroot 		int	fdes;
2267820Sroot 		struct	iovec *iovp;
22726474Skarels 		unsigned iovcnt;
22842922Smckusick 	} *uap;
22942922Smckusick 	int *retval;
23042922Smckusick {
23137728Smckusick 	register struct file *fp;
2327820Sroot 	struct uio auio;
23337728Smckusick 	register struct iovec *iov;
23444939Skarels 	struct iovec *saveiov;
23537728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
23637728Smckusick 	long i, cnt, error = 0;
23744939Skarels 	unsigned iovlen;
23837728Smckusick #ifdef KTRACE
23937728Smckusick 	struct iovec *ktriov = NULL;
24037728Smckusick #endif
2417820Sroot 
24237728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
24337728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
24437728Smckusick 	    (fp->f_flag & FWRITE) == 0)
24544405Skarels 		return (EBADF);
24644939Skarels 	/* note: can't use iovlen until iovcnt is validated */
24744939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
24837127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
24937728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
25044405Skarels 			return (EINVAL);
25144939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
25244939Skarels 		saveiov = iov;
25337127Skarels 	} else
25437127Skarels 		iov = aiov;
25537127Skarels 	auio.uio_iov = iov;
2567820Sroot 	auio.uio_iovcnt = uap->iovcnt;
25737728Smckusick 	auio.uio_rw = UIO_WRITE;
25837728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
25944939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
26037127Skarels 		goto done;
26137728Smckusick 	auio.uio_resid = 0;
26237728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
2637820Sroot 		if (iov->iov_len < 0) {
26437728Smckusick 			error = EINVAL;
26537728Smckusick 			goto done;
2667820Sroot 		}
26737728Smckusick 		auio.uio_resid += iov->iov_len;
26837728Smckusick 		if (auio.uio_resid < 0) {
26937728Smckusick 			error = EINVAL;
27037728Smckusick 			goto done;
2717820Sroot 		}
27213270Ssam 		iov++;
2737820Sroot 	}
27437127Skarels #ifdef KTRACE
27537728Smckusick 	/*
27637728Smckusick 	 * if tracing, save a copy of iovec
27737728Smckusick 	 */
27842922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
27937127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
28037728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
28137127Skarels 	}
28237127Skarels #endif
28337728Smckusick 	cnt = auio.uio_resid;
28440703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
28540703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
28640703Skarels 		    error == EINTR || error == EWOULDBLOCK))
28740703Skarels 			error = 0;
28840703Skarels 		if (error == EPIPE)
28942922Smckusick 			psignal(p, SIGPIPE);
29040703Skarels 	}
29137728Smckusick 	cnt -= auio.uio_resid;
29237127Skarels #ifdef KTRACE
29337127Skarels 	if (ktriov != NULL) {
29441178Smarc 		if (error == 0)
29542922Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
29643448Smckusick 				ktriov, cnt, error);
29737127Skarels 		FREE(ktriov, M_TEMP);
29837127Skarels 	}
29937127Skarels #endif
30042922Smckusick 	*retval = cnt;
30137728Smckusick done:
30237728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
30344939Skarels 		FREE(saveiov, M_IOV);
30444405Skarels 	return (error);
3057423Sroot }
3067423Sroot 
3077423Sroot /*
3087423Sroot  * Ioctl system call
3097423Sroot  */
31042922Smckusick /* ARGSUSED */
31142922Smckusick ioctl(p, uap, retval)
31242922Smckusick 	struct proc *p;
31342922Smckusick 	register struct args {
3147423Sroot 		int	fdes;
3157423Sroot 		int	cmd;
3167423Sroot 		caddr_t	cmarg;
31742922Smckusick 	} *uap;
31842922Smckusick 	int *retval;
31942922Smckusick {
32042922Smckusick 	register struct file *fp;
32140703Skarels 	register int com, error;
3227820Sroot 	register u_int size;
32331653Smckusick 	caddr_t memp = 0;
32430530Skarels #define STK_PARAMS	128
32533480Skarels 	char stkbuf[STK_PARAMS];
32633480Skarels 	caddr_t data = stkbuf;
3277423Sroot 
32837728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
32937728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
33044405Skarels 		return (EBADF);
33140703Skarels 	if ((fp->f_flag & (FREAD|FWRITE)) == 0)
33244405Skarels 		return (EBADF);
3337624Ssam 	com = uap->cmd;
3347624Ssam 
3357624Ssam 	if (com == FIOCLEX) {
3369592Ssam 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
33744405Skarels 		return (0);
3387423Sroot 	}
3397624Ssam 	if (com == FIONCLEX) {
3409592Ssam 		u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
34144405Skarels 		return (0);
3427423Sroot 	}
3437624Ssam 
3447624Ssam 	/*
3457624Ssam 	 * Interpret high order word to find
3467624Ssam 	 * amount of data to be copied to/from the
3477624Ssam 	 * user's address space.
3487624Ssam 	 */
34930530Skarels 	size = IOCPARM_LEN(com);
35040703Skarels 	if (size > IOCPARM_MAX)
35144405Skarels 		return (ENOTTY);
35233480Skarels 	if (size > sizeof (stkbuf)) {
35343383Smckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
35431653Smckusick 		data = memp;
35530530Skarels 	}
35610601Ssam 	if (com&IOC_IN) {
35710601Ssam 		if (size) {
35840703Skarels 			error = copyin(uap->cmarg, data, (u_int)size);
35940703Skarels 			if (error) {
36031653Smckusick 				if (memp)
36131653Smckusick 					free(memp, M_IOCTLOPS);
36244405Skarels 				return (error);
36331653Smckusick 			}
36410601Ssam 		} else
36510601Ssam 			*(caddr_t *)data = uap->cmarg;
36610601Ssam 	} else if ((com&IOC_OUT) && size)
36710601Ssam 		/*
36837127Skarels 		 * Zero the buffer so the user always
36937127Skarels 		 * gets back something deterministic.
37010601Ssam 		 */
37130530Skarels 		bzero(data, size);
37211284Ssam 	else if (com&IOC_VOID)
37311284Ssam 		*(caddr_t *)data = uap->cmarg;
3747423Sroot 
37512751Ssam 	switch (com) {
3767624Ssam 
37712751Ssam 	case FIONBIO:
37840703Skarels 		error = fset(fp, FNDELAY, *(int *)data);
37930530Skarels 		break;
38012751Ssam 
38112751Ssam 	case FIOASYNC:
38240703Skarels 		error = fset(fp, FASYNC, *(int *)data);
38330530Skarels 		break;
38412751Ssam 
38512751Ssam 	case FIOSETOWN:
38640703Skarels 		error = fsetown(fp, *(int *)data);
38730530Skarels 		break;
38812751Ssam 
38912751Ssam 	case FIOGETOWN:
39040703Skarels 		error = fgetown(fp, (int *)data);
39130530Skarels 		break;
39230530Skarels 	default:
39340703Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data);
39430530Skarels 		/*
39530530Skarels 		 * Copy any data to user, size was
39630530Skarels 		 * already set and checked above.
39730530Skarels 		 */
39840703Skarels 		if (error == 0 && (com&IOC_OUT) && size)
39940703Skarels 			error = copyout(data, uap->cmarg, (u_int)size);
40030530Skarels 		break;
4017423Sroot 	}
40231653Smckusick 	if (memp)
40331653Smckusick 		free(memp, M_IOCTLOPS);
40444405Skarels 	return (error);
4057423Sroot }
4067423Sroot 
40712751Ssam int	nselcoll;
40817593Skarels 
4097423Sroot /*
41012751Ssam  * Select system call.
4117423Sroot  */
41242922Smckusick select(p, uap, retval)
41342922Smckusick 	register struct proc *p;
41442922Smckusick 	register struct args {
41512751Ssam 		int	nd;
41623523Skarels 		fd_set	*in, *ou, *ex;
41712751Ssam 		struct	timeval *tv;
41842922Smckusick 	} *uap;
41942922Smckusick 	int *retval;
42042922Smckusick {
42123523Skarels 	fd_set ibits[3], obits[3];
42212751Ssam 	struct timeval atv;
42340703Skarels 	int s, ncoll, ni, error = 0, timo;
42412751Ssam 
42526277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
42626277Skarels 	bzero((caddr_t)obits, sizeof(obits));
42712751Ssam 	if (uap->nd > NOFILE)
42812751Ssam 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
42923523Skarels 	ni = howmany(uap->nd, NFDBITS);
43012751Ssam 
43112751Ssam #define	getbits(name, x) \
43212751Ssam 	if (uap->name) { \
43340703Skarels 		error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
43426277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
43540703Skarels 		if (error) \
43612751Ssam 			goto done; \
43717593Skarels 	}
43812751Ssam 	getbits(in, 0);
43912751Ssam 	getbits(ou, 1);
44012751Ssam 	getbits(ex, 2);
44112751Ssam #undef	getbits
44212751Ssam 
44312751Ssam 	if (uap->tv) {
44440703Skarels 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
44512751Ssam 			sizeof (atv));
44640703Skarels 		if (error)
44712751Ssam 			goto done;
44812751Ssam 		if (itimerfix(&atv)) {
44940703Skarels 			error = EINVAL;
45012751Ssam 			goto done;
45112751Ssam 		}
45217934Skarels 		s = splhigh(); timevaladd(&atv, &time); splx(s);
45340703Skarels 		timo = hzto(&atv);
45440703Skarels 	} else
45540703Skarels 		timo = 0;
45612751Ssam retry:
45712751Ssam 	ncoll = nselcoll;
45842922Smckusick 	p->p_flag |= SSEL;
45942922Smckusick 	error = selscan(ibits, obits, uap->nd, retval);
46042922Smckusick 	if (error || *retval)
46112751Ssam 		goto done;
46217934Skarels 	s = splhigh();
46312971Ssam 	/* this should be timercmp(&time, &atv, >=) */
46412971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
46512971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
46612751Ssam 		splx(s);
46712751Ssam 		goto done;
46812751Ssam 	}
46942922Smckusick 	if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
47012751Ssam 		splx(s);
47112751Ssam 		goto retry;
47212751Ssam 	}
47342922Smckusick 	p->p_flag &= ~SSEL;
47440703Skarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
47512751Ssam 	splx(s);
47640703Skarels 	if (error == 0)
47740703Skarels 		goto retry;
47812751Ssam done:
47942922Smckusick 	p->p_flag &= ~SSEL;
48040703Skarels 	/* select is not restarted after signals... */
48140703Skarels 	if (error == ERESTART)
48240703Skarels 		error = EINTR;
48340703Skarels 	if (error == EWOULDBLOCK)
48440703Skarels 		error = 0;
48512751Ssam #define	putbits(name, x) \
48612751Ssam 	if (uap->name) { \
48740703Skarels 		int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
48826277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
48940703Skarels 		if (error2) \
49040703Skarels 			error = error2; \
49112751Ssam 	}
49240703Skarels 	if (error == 0) {
49321106Skarels 		putbits(in, 0);
49421106Skarels 		putbits(ou, 1);
49521106Skarels 		putbits(ex, 2);
49612751Ssam #undef putbits
49721106Skarels 	}
49844405Skarels 	return (error);
49912751Ssam }
50012751Ssam 
50142922Smckusick selscan(ibits, obits, nfd, retval)
50223523Skarels 	fd_set *ibits, *obits;
50342922Smckusick 	int nfd, *retval;
50412751Ssam {
50523523Skarels 	register int which, i, j;
50623523Skarels 	register fd_mask bits;
50712751Ssam 	int flag;
50812751Ssam 	struct file *fp;
50942922Smckusick 	int error = 0, n = 0;
51012751Ssam 
51112751Ssam 	for (which = 0; which < 3; which++) {
51212751Ssam 		switch (which) {
51312751Ssam 
51412751Ssam 		case 0:
51512751Ssam 			flag = FREAD; break;
51612751Ssam 
51712751Ssam 		case 1:
51812751Ssam 			flag = FWRITE; break;
51912751Ssam 
52012751Ssam 		case 2:
52112751Ssam 			flag = 0; break;
52212751Ssam 		}
52323523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
52423523Skarels 			bits = ibits[which].fds_bits[i/NFDBITS];
52517593Skarels 			while ((j = ffs(bits)) && i + --j < nfd) {
52617593Skarels 				bits &= ~(1 << j);
52717593Skarels 				fp = u.u_ofile[i + j];
52817593Skarels 				if (fp == NULL) {
52942922Smckusick 					error = EBADF;
53017593Skarels 					break;
53117593Skarels 				}
53217593Skarels 				if ((*fp->f_ops->fo_select)(fp, flag)) {
53323523Skarels 					FD_SET(i + j, &obits[which]);
53417593Skarels 					n++;
53517593Skarels 				}
53612751Ssam 			}
53712751Ssam 		}
53812751Ssam 	}
53942922Smckusick 	*retval = n;
54042922Smckusick 	return (error);
54112751Ssam }
54212751Ssam 
5437423Sroot /*ARGSUSED*/
54412751Ssam seltrue(dev, flag)
54512751Ssam 	dev_t dev;
54612751Ssam 	int flag;
5477423Sroot {
5487423Sroot 
54912751Ssam 	return (1);
5507423Sroot }
5518103Sroot 
55212751Ssam selwakeup(p, coll)
55312751Ssam 	register struct proc *p;
55412751Ssam 	int coll;
5558103Sroot {
5568103Sroot 
55712751Ssam 	if (coll) {
55812751Ssam 		nselcoll++;
55912751Ssam 		wakeup((caddr_t)&selwait);
56012751Ssam 	}
56112751Ssam 	if (p) {
56217934Skarels 		int s = splhigh();
56317270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
56417270Skarels 			if (p->p_stat == SSLEEP)
56517270Skarels 				setrun(p);
56617270Skarels 			else
56717270Skarels 				unsleep(p);
56817270Skarels 		} else if (p->p_flag & SSEL)
56912751Ssam 			p->p_flag &= ~SSEL;
57012751Ssam 		splx(s);
57112751Ssam 	}
5728103Sroot }
573