xref: /csrg-svn/sys/kern/sys_generic.c (revision 44939)
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*44939Skarels  *	@(#)sys_generic.c	7.23 (Berkeley) 07/22/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  */
2742922Smckusick read(p, uap, retval)
2842922Smckusick 	struct proc *p;
2942922Smckusick 	register struct args {
307423Sroot 		int	fdes;
317423Sroot 		char	*cbuf;
327423Sroot 		unsigned count;
3342922Smckusick 	} *uap;
3442922Smckusick 	int *retval;
3542922Smckusick {
3637728Smckusick 	register struct file *fp;
377746Sroot 	struct uio auio;
387746Sroot 	struct iovec aiov;
3937728Smckusick 	long cnt, error = 0;
4037728Smckusick #ifdef KTRACE
4137728Smckusick 	struct iovec ktriov;
4237728Smckusick #endif
437423Sroot 
4437728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
4537728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
4637728Smckusick 	    (fp->f_flag & FREAD) == 0)
4744405Skarels 		return (EBADF);
487820Sroot 	aiov.iov_base = (caddr_t)uap->cbuf;
497820Sroot 	aiov.iov_len = uap->count;
507820Sroot 	auio.uio_iov = &aiov;
517820Sroot 	auio.uio_iovcnt = 1;
5237728Smckusick 	auio.uio_resid = uap->count;
5337728Smckusick 	auio.uio_rw = UIO_READ;
5437728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
5537728Smckusick #ifdef KTRACE
5637728Smckusick 	/*
5737728Smckusick 	 * if tracing, save a copy of iovec
5837728Smckusick 	 */
5942922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
6037728Smckusick 		ktriov = aiov;
6137728Smckusick #endif
6237728Smckusick 	cnt = uap->count;
6340703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
6440703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
6540703Skarels 		    error == EINTR || error == EWOULDBLOCK))
6640703Skarels 			error = 0;
6737728Smckusick 	cnt -= auio.uio_resid;
6837728Smckusick #ifdef KTRACE
6942922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
7043448Smckusick 		ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
7137728Smckusick #endif
7242922Smckusick 	*retval = cnt;
7344405Skarels 	return (error);
747820Sroot }
757820Sroot 
7642922Smckusick /*
7742922Smckusick  * Scatter read system call.
7842922Smckusick  */
7942922Smckusick readv(p, uap, retval)
8042922Smckusick 	struct proc *p;
8142922Smckusick 	register struct args {
827820Sroot 		int	fdes;
837820Sroot 		struct	iovec *iovp;
8426474Skarels 		unsigned iovcnt;
8542922Smckusick 	} *uap;
8642922Smckusick 	int *retval;
8742922Smckusick {
8837728Smckusick 	register struct file *fp;
897820Sroot 	struct uio auio;
9037728Smckusick 	register struct iovec *iov;
91*44939Skarels 	struct iovec *saveiov;
9237728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
9337728Smckusick 	long i, cnt, error = 0;
94*44939Skarels 	unsigned iovlen;
9537728Smckusick #ifdef KTRACE
9637728Smckusick 	struct iovec *ktriov = NULL;
9737728Smckusick #endif
987820Sroot 
9937728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
10037728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
10137728Smckusick 	    (fp->f_flag & FREAD) == 0)
10244405Skarels 		return (EBADF);
103*44939Skarels 	/* note: can't use iovlen until iovcnt is validated */
104*44939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
10537127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
10637728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
10744405Skarels 			return (EINVAL);
108*44939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
109*44939Skarels 		saveiov = iov;
11037127Skarels 	} else
11137127Skarels 		iov = aiov;
11237127Skarels 	auio.uio_iov = iov;
1137820Sroot 	auio.uio_iovcnt = uap->iovcnt;
11437728Smckusick 	auio.uio_rw = UIO_READ;
11537728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
116*44939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
11737127Skarels 		goto done;
11837728Smckusick 	auio.uio_resid = 0;
11937728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
12037728Smckusick 		if (iov->iov_len < 0) {
12137728Smckusick 			error = EINVAL;
12237728Smckusick 			goto done;
12337728Smckusick 		}
12437728Smckusick 		auio.uio_resid += iov->iov_len;
12537728Smckusick 		if (auio.uio_resid < 0) {
12637728Smckusick 			error = EINVAL;
12737728Smckusick 			goto done;
12837728Smckusick 		}
12937728Smckusick 		iov++;
13037728Smckusick 	}
13137728Smckusick #ifdef KTRACE
13237728Smckusick 	/*
13337728Smckusick 	 * if tracing, save a copy of iovec
13437728Smckusick 	 */
13542922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
13637728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
13737728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
13837728Smckusick 	}
13937728Smckusick #endif
14037728Smckusick 	cnt = auio.uio_resid;
14140703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
14240703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
14340703Skarels 		    error == EINTR || error == EWOULDBLOCK))
14440703Skarels 			error = 0;
14537728Smckusick 	cnt -= auio.uio_resid;
14637728Smckusick #ifdef KTRACE
14737728Smckusick 	if (ktriov != NULL) {
14841178Smarc 		if (error == 0)
14943448Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
15043448Smckusick 			    cnt, error);
15137728Smckusick 		FREE(ktriov, M_TEMP);
15237728Smckusick 	}
15337728Smckusick #endif
15442922Smckusick 	*retval = cnt;
15537127Skarels done:
15637728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
157*44939Skarels 		FREE(saveiov, M_IOV);
15844405Skarels 	return (error);
1597423Sroot }
1607423Sroot 
1617423Sroot /*
1627423Sroot  * Write system call
1637423Sroot  */
16442922Smckusick write(p, uap, retval)
16542922Smckusick 	struct proc *p;
16642922Smckusick 	register struct args {
1677423Sroot 		int	fdes;
1687423Sroot 		char	*cbuf;
16926474Skarels 		unsigned count;
17042922Smckusick 	} *uap;
17142922Smckusick 	int *retval;
17242922Smckusick {
17337728Smckusick 	register struct file *fp;
1747820Sroot 	struct uio auio;
1757820Sroot 	struct iovec aiov;
17637728Smckusick 	long cnt, error = 0;
17737728Smckusick #ifdef KTRACE
17837728Smckusick 	struct iovec ktriov;
17937728Smckusick #endif
1807423Sroot 
18137728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
18237728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
18337728Smckusick 	    (fp->f_flag & FWRITE) == 0)
18444405Skarels 		return (EBADF);
18537728Smckusick 	aiov.iov_base = (caddr_t)uap->cbuf;
18637728Smckusick 	aiov.iov_len = uap->count;
1877820Sroot 	auio.uio_iov = &aiov;
1887820Sroot 	auio.uio_iovcnt = 1;
18937728Smckusick 	auio.uio_resid = uap->count;
19037728Smckusick 	auio.uio_rw = UIO_WRITE;
19137728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
19237728Smckusick #ifdef KTRACE
19337728Smckusick 	/*
19437728Smckusick 	 * if tracing, save a copy of iovec
19537728Smckusick 	 */
19642922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
19737728Smckusick 		ktriov = aiov;
19837728Smckusick #endif
19937728Smckusick 	cnt = uap->count;
20040703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
20140703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
20240703Skarels 		    error == EINTR || error == EWOULDBLOCK))
20340703Skarels 			error = 0;
20440703Skarels 		if (error == EPIPE)
20542922Smckusick 			psignal(p, SIGPIPE);
20640703Skarels 	}
20737728Smckusick 	cnt -= auio.uio_resid;
20837728Smckusick #ifdef KTRACE
20942922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
21042922Smckusick 		ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
21143448Smckusick 		    &ktriov, cnt, error);
21237728Smckusick #endif
21342922Smckusick 	*retval = cnt;
21444405Skarels 	return (error);
2157820Sroot }
2167820Sroot 
21742922Smckusick /*
21842922Smckusick  * Gather write system call
21942922Smckusick  */
22042922Smckusick writev(p, uap, retval)
22142922Smckusick 	struct proc *p;
22242922Smckusick 	register struct args {
2237820Sroot 		int	fdes;
2247820Sroot 		struct	iovec *iovp;
22526474Skarels 		unsigned iovcnt;
22642922Smckusick 	} *uap;
22742922Smckusick 	int *retval;
22842922Smckusick {
22937728Smckusick 	register struct file *fp;
2307820Sroot 	struct uio auio;
23137728Smckusick 	register struct iovec *iov;
232*44939Skarels 	struct iovec *saveiov;
23337728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
23437728Smckusick 	long i, cnt, error = 0;
235*44939Skarels 	unsigned iovlen;
23637728Smckusick #ifdef KTRACE
23737728Smckusick 	struct iovec *ktriov = NULL;
23837728Smckusick #endif
2397820Sroot 
24037728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
24137728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
24237728Smckusick 	    (fp->f_flag & FWRITE) == 0)
24344405Skarels 		return (EBADF);
244*44939Skarels 	/* note: can't use iovlen until iovcnt is validated */
245*44939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
24637127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
24737728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
24844405Skarels 			return (EINVAL);
249*44939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
250*44939Skarels 		saveiov = iov;
25137127Skarels 	} else
25237127Skarels 		iov = aiov;
25337127Skarels 	auio.uio_iov = iov;
2547820Sroot 	auio.uio_iovcnt = uap->iovcnt;
25537728Smckusick 	auio.uio_rw = UIO_WRITE;
25637728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
257*44939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
25837127Skarels 		goto done;
25937728Smckusick 	auio.uio_resid = 0;
26037728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
2617820Sroot 		if (iov->iov_len < 0) {
26237728Smckusick 			error = EINVAL;
26337728Smckusick 			goto done;
2647820Sroot 		}
26537728Smckusick 		auio.uio_resid += iov->iov_len;
26637728Smckusick 		if (auio.uio_resid < 0) {
26737728Smckusick 			error = EINVAL;
26837728Smckusick 			goto done;
2697820Sroot 		}
27013270Ssam 		iov++;
2717820Sroot 	}
27237127Skarels #ifdef KTRACE
27337728Smckusick 	/*
27437728Smckusick 	 * if tracing, save a copy of iovec
27537728Smckusick 	 */
27642922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
27737127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
27837728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
27937127Skarels 	}
28037127Skarels #endif
28137728Smckusick 	cnt = auio.uio_resid;
28240703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
28340703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
28440703Skarels 		    error == EINTR || error == EWOULDBLOCK))
28540703Skarels 			error = 0;
28640703Skarels 		if (error == EPIPE)
28742922Smckusick 			psignal(p, SIGPIPE);
28840703Skarels 	}
28937728Smckusick 	cnt -= auio.uio_resid;
29037127Skarels #ifdef KTRACE
29137127Skarels 	if (ktriov != NULL) {
29241178Smarc 		if (error == 0)
29342922Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
29443448Smckusick 				ktriov, cnt, error);
29537127Skarels 		FREE(ktriov, M_TEMP);
29637127Skarels 	}
29737127Skarels #endif
29842922Smckusick 	*retval = cnt;
29937728Smckusick done:
30037728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
301*44939Skarels 		FREE(saveiov, M_IOV);
30244405Skarels 	return (error);
3037423Sroot }
3047423Sroot 
3057423Sroot /*
3067423Sroot  * Ioctl system call
3077423Sroot  */
30842922Smckusick /* ARGSUSED */
30942922Smckusick ioctl(p, uap, retval)
31042922Smckusick 	struct proc *p;
31142922Smckusick 	register struct args {
3127423Sroot 		int	fdes;
3137423Sroot 		int	cmd;
3147423Sroot 		caddr_t	cmarg;
31542922Smckusick 	} *uap;
31642922Smckusick 	int *retval;
31742922Smckusick {
31842922Smckusick 	register struct file *fp;
31940703Skarels 	register int com, error;
3207820Sroot 	register u_int size;
32131653Smckusick 	caddr_t memp = 0;
32230530Skarels #define STK_PARAMS	128
32333480Skarels 	char stkbuf[STK_PARAMS];
32433480Skarels 	caddr_t data = stkbuf;
3257423Sroot 
32637728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
32737728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
32844405Skarels 		return (EBADF);
32940703Skarels 	if ((fp->f_flag & (FREAD|FWRITE)) == 0)
33044405Skarels 		return (EBADF);
3317624Ssam 	com = uap->cmd;
3327624Ssam 
3337624Ssam 	if (com == FIOCLEX) {
3349592Ssam 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
33544405Skarels 		return (0);
3367423Sroot 	}
3377624Ssam 	if (com == FIONCLEX) {
3389592Ssam 		u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
33944405Skarels 		return (0);
3407423Sroot 	}
3417624Ssam 
3427624Ssam 	/*
3437624Ssam 	 * Interpret high order word to find
3447624Ssam 	 * amount of data to be copied to/from the
3457624Ssam 	 * user's address space.
3467624Ssam 	 */
34730530Skarels 	size = IOCPARM_LEN(com);
34840703Skarels 	if (size > IOCPARM_MAX)
34944405Skarels 		return (ENOTTY);
35033480Skarels 	if (size > sizeof (stkbuf)) {
35143383Smckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
35231653Smckusick 		data = memp;
35330530Skarels 	}
35410601Ssam 	if (com&IOC_IN) {
35510601Ssam 		if (size) {
35640703Skarels 			error = copyin(uap->cmarg, data, (u_int)size);
35740703Skarels 			if (error) {
35831653Smckusick 				if (memp)
35931653Smckusick 					free(memp, M_IOCTLOPS);
36044405Skarels 				return (error);
36131653Smckusick 			}
36210601Ssam 		} else
36310601Ssam 			*(caddr_t *)data = uap->cmarg;
36410601Ssam 	} else if ((com&IOC_OUT) && size)
36510601Ssam 		/*
36637127Skarels 		 * Zero the buffer so the user always
36737127Skarels 		 * gets back something deterministic.
36810601Ssam 		 */
36930530Skarels 		bzero(data, size);
37011284Ssam 	else if (com&IOC_VOID)
37111284Ssam 		*(caddr_t *)data = uap->cmarg;
3727423Sroot 
37312751Ssam 	switch (com) {
3747624Ssam 
37512751Ssam 	case FIONBIO:
37640703Skarels 		error = fset(fp, FNDELAY, *(int *)data);
37730530Skarels 		break;
37812751Ssam 
37912751Ssam 	case FIOASYNC:
38040703Skarels 		error = fset(fp, FASYNC, *(int *)data);
38130530Skarels 		break;
38212751Ssam 
38312751Ssam 	case FIOSETOWN:
38440703Skarels 		error = fsetown(fp, *(int *)data);
38530530Skarels 		break;
38612751Ssam 
38712751Ssam 	case FIOGETOWN:
38840703Skarels 		error = fgetown(fp, (int *)data);
38930530Skarels 		break;
39030530Skarels 	default:
39140703Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data);
39230530Skarels 		/*
39330530Skarels 		 * Copy any data to user, size was
39430530Skarels 		 * already set and checked above.
39530530Skarels 		 */
39640703Skarels 		if (error == 0 && (com&IOC_OUT) && size)
39740703Skarels 			error = copyout(data, uap->cmarg, (u_int)size);
39830530Skarels 		break;
3997423Sroot 	}
40031653Smckusick 	if (memp)
40131653Smckusick 		free(memp, M_IOCTLOPS);
40244405Skarels 	return (error);
4037423Sroot }
4047423Sroot 
40512751Ssam int	nselcoll;
40617593Skarels 
4077423Sroot /*
40812751Ssam  * Select system call.
4097423Sroot  */
41042922Smckusick select(p, uap, retval)
41142922Smckusick 	register struct proc *p;
41242922Smckusick 	register struct args {
41312751Ssam 		int	nd;
41423523Skarels 		fd_set	*in, *ou, *ex;
41512751Ssam 		struct	timeval *tv;
41642922Smckusick 	} *uap;
41742922Smckusick 	int *retval;
41842922Smckusick {
41923523Skarels 	fd_set ibits[3], obits[3];
42012751Ssam 	struct timeval atv;
42140703Skarels 	int s, ncoll, ni, error = 0, timo;
42212751Ssam 
42326277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
42426277Skarels 	bzero((caddr_t)obits, sizeof(obits));
42512751Ssam 	if (uap->nd > NOFILE)
42612751Ssam 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
42723523Skarels 	ni = howmany(uap->nd, NFDBITS);
42812751Ssam 
42912751Ssam #define	getbits(name, x) \
43012751Ssam 	if (uap->name) { \
43140703Skarels 		error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
43226277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
43340703Skarels 		if (error) \
43412751Ssam 			goto done; \
43517593Skarels 	}
43612751Ssam 	getbits(in, 0);
43712751Ssam 	getbits(ou, 1);
43812751Ssam 	getbits(ex, 2);
43912751Ssam #undef	getbits
44012751Ssam 
44112751Ssam 	if (uap->tv) {
44240703Skarels 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
44312751Ssam 			sizeof (atv));
44440703Skarels 		if (error)
44512751Ssam 			goto done;
44612751Ssam 		if (itimerfix(&atv)) {
44740703Skarels 			error = EINVAL;
44812751Ssam 			goto done;
44912751Ssam 		}
45017934Skarels 		s = splhigh(); timevaladd(&atv, &time); splx(s);
45140703Skarels 		timo = hzto(&atv);
45240703Skarels 	} else
45340703Skarels 		timo = 0;
45412751Ssam retry:
45512751Ssam 	ncoll = nselcoll;
45642922Smckusick 	p->p_flag |= SSEL;
45742922Smckusick 	error = selscan(ibits, obits, uap->nd, retval);
45842922Smckusick 	if (error || *retval)
45912751Ssam 		goto done;
46017934Skarels 	s = splhigh();
46112971Ssam 	/* this should be timercmp(&time, &atv, >=) */
46212971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
46312971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
46412751Ssam 		splx(s);
46512751Ssam 		goto done;
46612751Ssam 	}
46742922Smckusick 	if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
46812751Ssam 		splx(s);
46912751Ssam 		goto retry;
47012751Ssam 	}
47142922Smckusick 	p->p_flag &= ~SSEL;
47240703Skarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
47312751Ssam 	splx(s);
47440703Skarels 	if (error == 0)
47540703Skarels 		goto retry;
47612751Ssam done:
47742922Smckusick 	p->p_flag &= ~SSEL;
47840703Skarels 	/* select is not restarted after signals... */
47940703Skarels 	if (error == ERESTART)
48040703Skarels 		error = EINTR;
48140703Skarels 	if (error == EWOULDBLOCK)
48240703Skarels 		error = 0;
48312751Ssam #define	putbits(name, x) \
48412751Ssam 	if (uap->name) { \
48540703Skarels 		int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
48626277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
48740703Skarels 		if (error2) \
48840703Skarels 			error = error2; \
48912751Ssam 	}
49040703Skarels 	if (error == 0) {
49121106Skarels 		putbits(in, 0);
49221106Skarels 		putbits(ou, 1);
49321106Skarels 		putbits(ex, 2);
49412751Ssam #undef putbits
49521106Skarels 	}
49644405Skarels 	return (error);
49712751Ssam }
49812751Ssam 
49942922Smckusick selscan(ibits, obits, nfd, retval)
50023523Skarels 	fd_set *ibits, *obits;
50142922Smckusick 	int nfd, *retval;
50212751Ssam {
50323523Skarels 	register int which, i, j;
50423523Skarels 	register fd_mask bits;
50512751Ssam 	int flag;
50612751Ssam 	struct file *fp;
50742922Smckusick 	int error = 0, n = 0;
50812751Ssam 
50912751Ssam 	for (which = 0; which < 3; which++) {
51012751Ssam 		switch (which) {
51112751Ssam 
51212751Ssam 		case 0:
51312751Ssam 			flag = FREAD; break;
51412751Ssam 
51512751Ssam 		case 1:
51612751Ssam 			flag = FWRITE; break;
51712751Ssam 
51812751Ssam 		case 2:
51912751Ssam 			flag = 0; break;
52012751Ssam 		}
52123523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
52223523Skarels 			bits = ibits[which].fds_bits[i/NFDBITS];
52317593Skarels 			while ((j = ffs(bits)) && i + --j < nfd) {
52417593Skarels 				bits &= ~(1 << j);
52517593Skarels 				fp = u.u_ofile[i + j];
52617593Skarels 				if (fp == NULL) {
52742922Smckusick 					error = EBADF;
52817593Skarels 					break;
52917593Skarels 				}
53017593Skarels 				if ((*fp->f_ops->fo_select)(fp, flag)) {
53123523Skarels 					FD_SET(i + j, &obits[which]);
53217593Skarels 					n++;
53317593Skarels 				}
53412751Ssam 			}
53512751Ssam 		}
53612751Ssam 	}
53742922Smckusick 	*retval = n;
53842922Smckusick 	return (error);
53912751Ssam }
54012751Ssam 
5417423Sroot /*ARGSUSED*/
54212751Ssam seltrue(dev, flag)
54312751Ssam 	dev_t dev;
54412751Ssam 	int flag;
5457423Sroot {
5467423Sroot 
54712751Ssam 	return (1);
5487423Sroot }
5498103Sroot 
55012751Ssam selwakeup(p, coll)
55112751Ssam 	register struct proc *p;
55212751Ssam 	int coll;
5538103Sroot {
5548103Sroot 
55512751Ssam 	if (coll) {
55612751Ssam 		nselcoll++;
55712751Ssam 		wakeup((caddr_t)&selwait);
55812751Ssam 	}
55912751Ssam 	if (p) {
56017934Skarels 		int s = splhigh();
56117270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
56217270Skarels 			if (p->p_stat == SSLEEP)
56317270Skarels 				setrun(p);
56417270Skarels 			else
56517270Skarels 				unsleep(p);
56617270Skarels 		} else if (p->p_flag & SSEL)
56712751Ssam 			p->p_flag &= ~SSEL;
56812751Ssam 		splx(s);
56912751Ssam 	}
5708103Sroot }
571