xref: /csrg-svn/sys/kern/sys_generic.c (revision 45914)
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*45914Smckusick  *	@(#)sys_generic.c	7.25 (Berkeley) 01/10/91
823384Smckusick  */
97423Sroot 
1017094Sbloom #include "param.h"
1117094Sbloom #include "systm.h"
1244405Skarels #include "user.h"
13*45914Smckusick #include "filedesc.h"
1417094Sbloom #include "ioctl.h"
1517094Sbloom #include "file.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;
39*45914Smckusick 	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 
47*45914Smckusick 	if (((unsigned)uap->fdes) >= fdp->fd_maxfiles ||
48*45914Smckusick 	    (fp = OFILE(fdp, 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;
5837728Smckusick #ifdef KTRACE
5937728Smckusick 	/*
6037728Smckusick 	 * if tracing, save a copy of iovec
6137728Smckusick 	 */
6242922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
6337728Smckusick 		ktriov = aiov;
6437728Smckusick #endif
6537728Smckusick 	cnt = uap->count;
6640703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
6740703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
6840703Skarels 		    error == EINTR || error == EWOULDBLOCK))
6940703Skarels 			error = 0;
7037728Smckusick 	cnt -= auio.uio_resid;
7137728Smckusick #ifdef KTRACE
7242922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
7343448Smckusick 		ktrgenio(p->p_tracep, uap->fdes, UIO_READ, &ktriov, cnt, error);
7437728Smckusick #endif
7542922Smckusick 	*retval = cnt;
7644405Skarels 	return (error);
777820Sroot }
787820Sroot 
7942922Smckusick /*
8042922Smckusick  * Scatter read system call.
8142922Smckusick  */
8245122Sbostic /* ARGSUSED */
8342922Smckusick readv(p, uap, retval)
8442922Smckusick 	struct proc *p;
8542922Smckusick 	register struct args {
867820Sroot 		int	fdes;
877820Sroot 		struct	iovec *iovp;
8826474Skarels 		unsigned iovcnt;
8942922Smckusick 	} *uap;
9042922Smckusick 	int *retval;
9142922Smckusick {
9237728Smckusick 	register struct file *fp;
93*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
947820Sroot 	struct uio auio;
9537728Smckusick 	register struct iovec *iov;
9644939Skarels 	struct iovec *saveiov;
9737728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
9837728Smckusick 	long i, cnt, error = 0;
9944939Skarels 	unsigned iovlen;
10037728Smckusick #ifdef KTRACE
10137728Smckusick 	struct iovec *ktriov = NULL;
10237728Smckusick #endif
1037820Sroot 
104*45914Smckusick 	if (((unsigned)uap->fdes) >= fdp->fd_maxfiles ||
105*45914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL ||
10637728Smckusick 	    (fp->f_flag & FREAD) == 0)
10744405Skarels 		return (EBADF);
10844939Skarels 	/* note: can't use iovlen until iovcnt is validated */
10944939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
11037127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
11137728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
11244405Skarels 			return (EINVAL);
11344939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
11444939Skarels 		saveiov = iov;
11537127Skarels 	} else
11637127Skarels 		iov = aiov;
11737127Skarels 	auio.uio_iov = iov;
1187820Sroot 	auio.uio_iovcnt = uap->iovcnt;
11937728Smckusick 	auio.uio_rw = UIO_READ;
12037728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
12144939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
12237127Skarels 		goto done;
12337728Smckusick 	auio.uio_resid = 0;
12437728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
12537728Smckusick 		if (iov->iov_len < 0) {
12637728Smckusick 			error = EINVAL;
12737728Smckusick 			goto done;
12837728Smckusick 		}
12937728Smckusick 		auio.uio_resid += iov->iov_len;
13037728Smckusick 		if (auio.uio_resid < 0) {
13137728Smckusick 			error = EINVAL;
13237728Smckusick 			goto done;
13337728Smckusick 		}
13437728Smckusick 		iov++;
13537728Smckusick 	}
13637728Smckusick #ifdef KTRACE
13737728Smckusick 	/*
13837728Smckusick 	 * if tracing, save a copy of iovec
13937728Smckusick 	 */
14042922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
14137728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
14237728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
14337728Smckusick 	}
14437728Smckusick #endif
14537728Smckusick 	cnt = auio.uio_resid;
14640703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
14740703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
14840703Skarels 		    error == EINTR || error == EWOULDBLOCK))
14940703Skarels 			error = 0;
15037728Smckusick 	cnt -= auio.uio_resid;
15137728Smckusick #ifdef KTRACE
15237728Smckusick 	if (ktriov != NULL) {
15341178Smarc 		if (error == 0)
15443448Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_READ, ktriov,
15543448Smckusick 			    cnt, error);
15637728Smckusick 		FREE(ktriov, M_TEMP);
15737728Smckusick 	}
15837728Smckusick #endif
15942922Smckusick 	*retval = cnt;
16037127Skarels done:
16137728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
16244939Skarels 		FREE(saveiov, M_IOV);
16344405Skarels 	return (error);
1647423Sroot }
1657423Sroot 
1667423Sroot /*
1677423Sroot  * Write system call
1687423Sroot  */
16942922Smckusick write(p, uap, retval)
17042922Smckusick 	struct proc *p;
17142922Smckusick 	register struct args {
1727423Sroot 		int	fdes;
1737423Sroot 		char	*cbuf;
17426474Skarels 		unsigned count;
17542922Smckusick 	} *uap;
17642922Smckusick 	int *retval;
17742922Smckusick {
17837728Smckusick 	register struct file *fp;
179*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
1807820Sroot 	struct uio auio;
1817820Sroot 	struct iovec aiov;
18237728Smckusick 	long cnt, error = 0;
18337728Smckusick #ifdef KTRACE
18437728Smckusick 	struct iovec ktriov;
18537728Smckusick #endif
1867423Sroot 
187*45914Smckusick 	if (((unsigned)uap->fdes) >= fdp->fd_maxfiles ||
188*45914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL ||
18937728Smckusick 	    (fp->f_flag & FWRITE) == 0)
19044405Skarels 		return (EBADF);
19137728Smckusick 	aiov.iov_base = (caddr_t)uap->cbuf;
19237728Smckusick 	aiov.iov_len = uap->count;
1937820Sroot 	auio.uio_iov = &aiov;
1947820Sroot 	auio.uio_iovcnt = 1;
19537728Smckusick 	auio.uio_resid = uap->count;
19637728Smckusick 	auio.uio_rw = UIO_WRITE;
19737728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
19837728Smckusick #ifdef KTRACE
19937728Smckusick 	/*
20037728Smckusick 	 * if tracing, save a copy of iovec
20137728Smckusick 	 */
20242922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
20337728Smckusick 		ktriov = aiov;
20437728Smckusick #endif
20537728Smckusick 	cnt = uap->count;
20640703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
20740703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
20840703Skarels 		    error == EINTR || error == EWOULDBLOCK))
20940703Skarels 			error = 0;
21040703Skarels 		if (error == EPIPE)
21142922Smckusick 			psignal(p, SIGPIPE);
21240703Skarels 	}
21337728Smckusick 	cnt -= auio.uio_resid;
21437728Smckusick #ifdef KTRACE
21542922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
21642922Smckusick 		ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
21743448Smckusick 		    &ktriov, cnt, error);
21837728Smckusick #endif
21942922Smckusick 	*retval = cnt;
22044405Skarels 	return (error);
2217820Sroot }
2227820Sroot 
22342922Smckusick /*
22442922Smckusick  * Gather write system call
22542922Smckusick  */
22642922Smckusick writev(p, uap, retval)
22742922Smckusick 	struct proc *p;
22842922Smckusick 	register struct args {
2297820Sroot 		int	fdes;
2307820Sroot 		struct	iovec *iovp;
23126474Skarels 		unsigned iovcnt;
23242922Smckusick 	} *uap;
23342922Smckusick 	int *retval;
23442922Smckusick {
23537728Smckusick 	register struct file *fp;
236*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
2377820Sroot 	struct uio auio;
23837728Smckusick 	register struct iovec *iov;
23944939Skarels 	struct iovec *saveiov;
24037728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
24137728Smckusick 	long i, cnt, error = 0;
24244939Skarels 	unsigned iovlen;
24337728Smckusick #ifdef KTRACE
24437728Smckusick 	struct iovec *ktriov = NULL;
24537728Smckusick #endif
2467820Sroot 
247*45914Smckusick 	if (((unsigned)uap->fdes) >= fdp->fd_maxfiles ||
248*45914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL ||
24937728Smckusick 	    (fp->f_flag & FWRITE) == 0)
25044405Skarels 		return (EBADF);
25144939Skarels 	/* note: can't use iovlen until iovcnt is validated */
25244939Skarels 	iovlen = uap->iovcnt * sizeof (struct iovec);
25337127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
25437728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
25544405Skarels 			return (EINVAL);
25644939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
25744939Skarels 		saveiov = iov;
25837127Skarels 	} else
25937127Skarels 		iov = aiov;
26037127Skarels 	auio.uio_iov = iov;
2617820Sroot 	auio.uio_iovcnt = uap->iovcnt;
26237728Smckusick 	auio.uio_rw = UIO_WRITE;
26337728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
26444939Skarels 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen))
26537127Skarels 		goto done;
26637728Smckusick 	auio.uio_resid = 0;
26737728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
2687820Sroot 		if (iov->iov_len < 0) {
26937728Smckusick 			error = EINVAL;
27037728Smckusick 			goto done;
2717820Sroot 		}
27237728Smckusick 		auio.uio_resid += iov->iov_len;
27337728Smckusick 		if (auio.uio_resid < 0) {
27437728Smckusick 			error = EINVAL;
27537728Smckusick 			goto done;
2767820Sroot 		}
27713270Ssam 		iov++;
2787820Sroot 	}
27937127Skarels #ifdef KTRACE
28037728Smckusick 	/*
28137728Smckusick 	 * if tracing, save a copy of iovec
28237728Smckusick 	 */
28342922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
28437127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
28537728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
28637127Skarels 	}
28737127Skarels #endif
28837728Smckusick 	cnt = auio.uio_resid;
28940703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
29040703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
29140703Skarels 		    error == EINTR || error == EWOULDBLOCK))
29240703Skarels 			error = 0;
29340703Skarels 		if (error == EPIPE)
29442922Smckusick 			psignal(p, SIGPIPE);
29540703Skarels 	}
29637728Smckusick 	cnt -= auio.uio_resid;
29737127Skarels #ifdef KTRACE
29837127Skarels 	if (ktriov != NULL) {
29941178Smarc 		if (error == 0)
30042922Smckusick 			ktrgenio(p->p_tracep, uap->fdes, UIO_WRITE,
30143448Smckusick 				ktriov, cnt, error);
30237127Skarels 		FREE(ktriov, M_TEMP);
30337127Skarels 	}
30437127Skarels #endif
30542922Smckusick 	*retval = cnt;
30637728Smckusick done:
30737728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
30844939Skarels 		FREE(saveiov, M_IOV);
30944405Skarels 	return (error);
3107423Sroot }
3117423Sroot 
3127423Sroot /*
3137423Sroot  * Ioctl system call
3147423Sroot  */
31542922Smckusick /* ARGSUSED */
31642922Smckusick ioctl(p, uap, retval)
31742922Smckusick 	struct proc *p;
31842922Smckusick 	register struct args {
3197423Sroot 		int	fdes;
3207423Sroot 		int	cmd;
3217423Sroot 		caddr_t	cmarg;
32242922Smckusick 	} *uap;
32342922Smckusick 	int *retval;
32442922Smckusick {
32542922Smckusick 	register struct file *fp;
326*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
32740703Skarels 	register int com, error;
3287820Sroot 	register u_int size;
32931653Smckusick 	caddr_t memp = 0;
33030530Skarels #define STK_PARAMS	128
33133480Skarels 	char stkbuf[STK_PARAMS];
33233480Skarels 	caddr_t data = stkbuf;
3337423Sroot 
334*45914Smckusick 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
335*45914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
33644405Skarels 		return (EBADF);
33740703Skarels 	if ((fp->f_flag & (FREAD|FWRITE)) == 0)
33844405Skarels 		return (EBADF);
3397624Ssam 	com = uap->cmd;
3407624Ssam 
3417624Ssam 	if (com == FIOCLEX) {
342*45914Smckusick 		OFILEFLAGS(fdp, uap->fdes) |= UF_EXCLOSE;
34344405Skarels 		return (0);
3447423Sroot 	}
3457624Ssam 	if (com == FIONCLEX) {
346*45914Smckusick 		OFILEFLAGS(fdp, uap->fdes) &= ~UF_EXCLOSE;
34744405Skarels 		return (0);
3487423Sroot 	}
3497624Ssam 
3507624Ssam 	/*
3517624Ssam 	 * Interpret high order word to find
3527624Ssam 	 * amount of data to be copied to/from the
3537624Ssam 	 * user's address space.
3547624Ssam 	 */
35530530Skarels 	size = IOCPARM_LEN(com);
35640703Skarels 	if (size > IOCPARM_MAX)
35744405Skarels 		return (ENOTTY);
35833480Skarels 	if (size > sizeof (stkbuf)) {
35943383Smckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
36031653Smckusick 		data = memp;
36130530Skarels 	}
36210601Ssam 	if (com&IOC_IN) {
36310601Ssam 		if (size) {
36440703Skarels 			error = copyin(uap->cmarg, data, (u_int)size);
36540703Skarels 			if (error) {
36631653Smckusick 				if (memp)
36731653Smckusick 					free(memp, M_IOCTLOPS);
36844405Skarels 				return (error);
36931653Smckusick 			}
37010601Ssam 		} else
37110601Ssam 			*(caddr_t *)data = uap->cmarg;
37210601Ssam 	} else if ((com&IOC_OUT) && size)
37310601Ssam 		/*
37437127Skarels 		 * Zero the buffer so the user always
37537127Skarels 		 * gets back something deterministic.
37610601Ssam 		 */
37730530Skarels 		bzero(data, size);
37811284Ssam 	else if (com&IOC_VOID)
37911284Ssam 		*(caddr_t *)data = uap->cmarg;
3807423Sroot 
38112751Ssam 	switch (com) {
3827624Ssam 
38312751Ssam 	case FIONBIO:
38440703Skarels 		error = fset(fp, FNDELAY, *(int *)data);
38530530Skarels 		break;
38612751Ssam 
38712751Ssam 	case FIOASYNC:
38840703Skarels 		error = fset(fp, FASYNC, *(int *)data);
38930530Skarels 		break;
39012751Ssam 
39112751Ssam 	case FIOSETOWN:
39240703Skarels 		error = fsetown(fp, *(int *)data);
39330530Skarels 		break;
39412751Ssam 
39512751Ssam 	case FIOGETOWN:
39640703Skarels 		error = fgetown(fp, (int *)data);
39730530Skarels 		break;
39830530Skarels 	default:
39940703Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data);
40030530Skarels 		/*
40130530Skarels 		 * Copy any data to user, size was
40230530Skarels 		 * already set and checked above.
40330530Skarels 		 */
40440703Skarels 		if (error == 0 && (com&IOC_OUT) && size)
40540703Skarels 			error = copyout(data, uap->cmarg, (u_int)size);
40630530Skarels 		break;
4077423Sroot 	}
40831653Smckusick 	if (memp)
40931653Smckusick 		free(memp, M_IOCTLOPS);
41044405Skarels 	return (error);
4117423Sroot }
4127423Sroot 
41312751Ssam int	nselcoll;
41417593Skarels 
4157423Sroot /*
41612751Ssam  * Select system call.
4177423Sroot  */
41842922Smckusick select(p, uap, retval)
41942922Smckusick 	register struct proc *p;
42042922Smckusick 	register struct args {
42112751Ssam 		int	nd;
42223523Skarels 		fd_set	*in, *ou, *ex;
42312751Ssam 		struct	timeval *tv;
42442922Smckusick 	} *uap;
42542922Smckusick 	int *retval;
42642922Smckusick {
42723523Skarels 	fd_set ibits[3], obits[3];
42812751Ssam 	struct timeval atv;
42940703Skarels 	int s, ncoll, ni, error = 0, timo;
43012751Ssam 
43126277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
43226277Skarels 	bzero((caddr_t)obits, sizeof(obits));
433*45914Smckusick 	if (uap->nd > p->p_fd->fd_maxfiles)
434*45914Smckusick 		uap->nd = p->p_fd->fd_maxfiles;	/* forgiving; slightly wrong */
43523523Skarels 	ni = howmany(uap->nd, NFDBITS);
43612751Ssam 
43712751Ssam #define	getbits(name, x) \
43812751Ssam 	if (uap->name) { \
43940703Skarels 		error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
44026277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
44140703Skarels 		if (error) \
44212751Ssam 			goto done; \
44317593Skarels 	}
44412751Ssam 	getbits(in, 0);
44512751Ssam 	getbits(ou, 1);
44612751Ssam 	getbits(ex, 2);
44712751Ssam #undef	getbits
44812751Ssam 
44912751Ssam 	if (uap->tv) {
45040703Skarels 		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
45112751Ssam 			sizeof (atv));
45240703Skarels 		if (error)
45312751Ssam 			goto done;
45412751Ssam 		if (itimerfix(&atv)) {
45540703Skarels 			error = EINVAL;
45612751Ssam 			goto done;
45712751Ssam 		}
45817934Skarels 		s = splhigh(); timevaladd(&atv, &time); splx(s);
45940703Skarels 		timo = hzto(&atv);
46040703Skarels 	} else
46140703Skarels 		timo = 0;
46212751Ssam retry:
46312751Ssam 	ncoll = nselcoll;
46442922Smckusick 	p->p_flag |= SSEL;
465*45914Smckusick 	error = selscan(p->p_fd, ibits, obits, uap->nd, retval);
46642922Smckusick 	if (error || *retval)
46712751Ssam 		goto done;
46817934Skarels 	s = splhigh();
46912971Ssam 	/* this should be timercmp(&time, &atv, >=) */
47012971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
47112971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
47212751Ssam 		splx(s);
47312751Ssam 		goto done;
47412751Ssam 	}
47542922Smckusick 	if ((p->p_flag & SSEL) == 0 || nselcoll != ncoll) {
47612751Ssam 		splx(s);
47712751Ssam 		goto retry;
47812751Ssam 	}
47942922Smckusick 	p->p_flag &= ~SSEL;
48040703Skarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
48112751Ssam 	splx(s);
48240703Skarels 	if (error == 0)
48340703Skarels 		goto retry;
48412751Ssam done:
48542922Smckusick 	p->p_flag &= ~SSEL;
48640703Skarels 	/* select is not restarted after signals... */
48740703Skarels 	if (error == ERESTART)
48840703Skarels 		error = EINTR;
48940703Skarels 	if (error == EWOULDBLOCK)
49040703Skarels 		error = 0;
49112751Ssam #define	putbits(name, x) \
49212751Ssam 	if (uap->name) { \
49340703Skarels 		int error2 = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
49426277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
49540703Skarels 		if (error2) \
49640703Skarels 			error = error2; \
49712751Ssam 	}
49840703Skarels 	if (error == 0) {
49921106Skarels 		putbits(in, 0);
50021106Skarels 		putbits(ou, 1);
50121106Skarels 		putbits(ex, 2);
50212751Ssam #undef putbits
50321106Skarels 	}
50444405Skarels 	return (error);
50512751Ssam }
50612751Ssam 
507*45914Smckusick selscan(fdp, ibits, obits, nfd, retval)
508*45914Smckusick 	register struct filedesc *fdp;
50923523Skarels 	fd_set *ibits, *obits;
51042922Smckusick 	int nfd, *retval;
51112751Ssam {
51223523Skarels 	register int which, i, j;
51323523Skarels 	register fd_mask bits;
51412751Ssam 	int flag;
51512751Ssam 	struct file *fp;
51642922Smckusick 	int error = 0, n = 0;
51712751Ssam 
51812751Ssam 	for (which = 0; which < 3; which++) {
51912751Ssam 		switch (which) {
52012751Ssam 
52112751Ssam 		case 0:
52212751Ssam 			flag = FREAD; break;
52312751Ssam 
52412751Ssam 		case 1:
52512751Ssam 			flag = FWRITE; break;
52612751Ssam 
52712751Ssam 		case 2:
52812751Ssam 			flag = 0; break;
52912751Ssam 		}
53023523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
53123523Skarels 			bits = ibits[which].fds_bits[i/NFDBITS];
53217593Skarels 			while ((j = ffs(bits)) && i + --j < nfd) {
53317593Skarels 				bits &= ~(1 << j);
534*45914Smckusick 				fp = OFILE(fdp, i + j);
53517593Skarels 				if (fp == NULL) {
53642922Smckusick 					error = EBADF;
53717593Skarels 					break;
53817593Skarels 				}
53917593Skarels 				if ((*fp->f_ops->fo_select)(fp, flag)) {
54023523Skarels 					FD_SET(i + j, &obits[which]);
54117593Skarels 					n++;
54217593Skarels 				}
54312751Ssam 			}
54412751Ssam 		}
54512751Ssam 	}
54642922Smckusick 	*retval = n;
54742922Smckusick 	return (error);
54812751Ssam }
54912751Ssam 
5507423Sroot /*ARGSUSED*/
55112751Ssam seltrue(dev, flag)
55212751Ssam 	dev_t dev;
55312751Ssam 	int flag;
5547423Sroot {
5557423Sroot 
55612751Ssam 	return (1);
5577423Sroot }
5588103Sroot 
55912751Ssam selwakeup(p, coll)
56012751Ssam 	register struct proc *p;
56112751Ssam 	int coll;
5628103Sroot {
5638103Sroot 
56412751Ssam 	if (coll) {
56512751Ssam 		nselcoll++;
56612751Ssam 		wakeup((caddr_t)&selwait);
56712751Ssam 	}
56812751Ssam 	if (p) {
56917934Skarels 		int s = splhigh();
57017270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
57117270Skarels 			if (p->p_stat == SSLEEP)
57217270Skarels 				setrun(p);
57317270Skarels 			else
57417270Skarels 				unsleep(p);
57517270Skarels 		} else if (p->p_flag & SSEL)
57612751Ssam 			p->p_flag &= ~SSEL;
57712751Ssam 		splx(s);
57812751Ssam 	}
5798103Sroot }
580