xref: /csrg-svn/sys/kern/sys_generic.c (revision 68316)
123384Smckusick /*
263865Sbostic  * Copyright (c) 1982, 1986, 1989, 1993
363865Sbostic  *	The Regents of the University of California.  All rights reserved.
465771Sbostic  * (c) UNIX System Laboratories, Inc.
565771Sbostic  * All or some portions of this file are derived from material licensed
665771Sbostic  * to the University of California by American Telephone and Telegraph
765771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic  * the permission of UNIX System Laboratories, Inc.
923384Smckusick  *
1044444Sbostic  * %sccs.include.redist.c%
1137728Smckusick  *
12*68316Scgd  *	@(#)sys_generic.c	8.9 (Berkeley) 02/14/95
1323384Smckusick  */
147423Sroot 
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/filedesc.h>
1856517Sbostic #include <sys/ioctl.h>
1956517Sbostic #include <sys/file.h>
2056517Sbostic #include <sys/proc.h>
2156517Sbostic #include <sys/socketvar.h>
2256517Sbostic #include <sys/uio.h>
2356517Sbostic #include <sys/kernel.h>
2456517Sbostic #include <sys/stat.h>
2556517Sbostic #include <sys/malloc.h>
2637127Skarels #ifdef KTRACE
2756517Sbostic #include <sys/ktrace.h>
2837127Skarels #endif
297423Sroot 
30*68316Scgd #include <sys/mount.h>
31*68316Scgd #include <sys/syscallargs.h>
32*68316Scgd 
337423Sroot /*
347423Sroot  * Read system call.
357423Sroot  */
3645122Sbostic /* ARGSUSED */
37*68316Scgd int
read(p,uap,retval)3842922Smckusick read(p, uap, retval)
3942922Smckusick 	struct proc *p;
40*68316Scgd 	register struct read_args /* {
41*68316Scgd 		syscallarg(int) fd;
42*68316Scgd 		syscallarg(char *) buf;
43*68316Scgd 		syscallarg(u_int) nbyte;
44*68316Scgd 	} */ *uap;
45*68316Scgd 	register_t *retval;
4642922Smckusick {
4737728Smckusick 	register struct file *fp;
4845914Smckusick 	register struct filedesc *fdp = p->p_fd;
497746Sroot 	struct uio auio;
507746Sroot 	struct iovec aiov;
5137728Smckusick 	long cnt, error = 0;
5237728Smckusick #ifdef KTRACE
5337728Smckusick 	struct iovec ktriov;
5437728Smckusick #endif
557423Sroot 
56*68316Scgd 	if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
57*68316Scgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
5837728Smckusick 	    (fp->f_flag & FREAD) == 0)
5944405Skarels 		return (EBADF);
60*68316Scgd 	aiov.iov_base = (caddr_t)SCARG(uap, buf);
61*68316Scgd 	aiov.iov_len = SCARG(uap, nbyte);
627820Sroot 	auio.uio_iov = &aiov;
637820Sroot 	auio.uio_iovcnt = 1;
64*68316Scgd 	auio.uio_resid = SCARG(uap, nbyte);
6537728Smckusick 	auio.uio_rw = UIO_READ;
6637728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
6748027Smckusick 	auio.uio_procp = p;
6837728Smckusick #ifdef KTRACE
6937728Smckusick 	/*
7037728Smckusick 	 * if tracing, save a copy of iovec
7137728Smckusick 	 */
7242922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
7337728Smckusick 		ktriov = aiov;
7437728Smckusick #endif
75*68316Scgd 	cnt = SCARG(uap, nbyte);
7640703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
7740703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
7840703Skarels 		    error == EINTR || error == EWOULDBLOCK))
7940703Skarels 			error = 0;
8037728Smckusick 	cnt -= auio.uio_resid;
8137728Smckusick #ifdef KTRACE
8242922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
83*68316Scgd 		ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, &ktriov,
84*68316Scgd 		    cnt, error);
8537728Smckusick #endif
8642922Smckusick 	*retval = cnt;
8744405Skarels 	return (error);
887820Sroot }
897820Sroot 
9042922Smckusick /*
9142922Smckusick  * Scatter read system call.
9242922Smckusick  */
93*68316Scgd int
readv(p,uap,retval)9442922Smckusick readv(p, uap, retval)
9542922Smckusick 	struct proc *p;
96*68316Scgd 	register struct readv_args /* {
97*68316Scgd 		syscallarg(int) fd;
98*68316Scgd 		syscallarg(struct iovec *) iovp;
99*68316Scgd 		syscallarg(u_int) iovcnt;
100*68316Scgd 	} */ *uap;
101*68316Scgd 	register_t *retval;
10242922Smckusick {
10337728Smckusick 	register struct file *fp;
10445914Smckusick 	register struct filedesc *fdp = p->p_fd;
1057820Sroot 	struct uio auio;
10637728Smckusick 	register struct iovec *iov;
10752481Storek 	struct iovec *needfree;
10837728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
10937728Smckusick 	long i, cnt, error = 0;
11064409Sbostic 	u_int iovlen;
11137728Smckusick #ifdef KTRACE
11237728Smckusick 	struct iovec *ktriov = NULL;
11337728Smckusick #endif
1147820Sroot 
115*68316Scgd 	if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
116*68316Scgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
11737728Smckusick 	    (fp->f_flag & FREAD) == 0)
11844405Skarels 		return (EBADF);
11944939Skarels 	/* note: can't use iovlen until iovcnt is validated */
120*68316Scgd 	iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
121*68316Scgd 	if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
122*68316Scgd 		if (SCARG(uap, iovcnt) > UIO_MAXIOV)
12344405Skarels 			return (EINVAL);
12444939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
12552481Storek 		needfree = iov;
12652481Storek 	} else {
12737127Skarels 		iov = aiov;
12852481Storek 		needfree = NULL;
12952481Storek 	}
13037127Skarels 	auio.uio_iov = iov;
131*68316Scgd 	auio.uio_iovcnt = SCARG(uap, iovcnt);
13237728Smckusick 	auio.uio_rw = UIO_READ;
13337728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
13448027Smckusick 	auio.uio_procp = p;
135*68316Scgd 	if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
13637127Skarels 		goto done;
13737728Smckusick 	auio.uio_resid = 0;
138*68316Scgd 	for (i = 0; i < SCARG(uap, iovcnt); i++) {
13967491Smckusick 		if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
14037728Smckusick 			error = EINVAL;
14137728Smckusick 			goto done;
14237728Smckusick 		}
14337728Smckusick 		auio.uio_resid += iov->iov_len;
14437728Smckusick 		iov++;
14537728Smckusick 	}
14637728Smckusick #ifdef KTRACE
14737728Smckusick 	/*
14837728Smckusick 	 * if tracing, save a copy of iovec
14937728Smckusick 	 */
15042922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
15137728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
15237728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
15337728Smckusick 	}
15437728Smckusick #endif
15537728Smckusick 	cnt = auio.uio_resid;
15640703Skarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
15740703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
15840703Skarels 		    error == EINTR || error == EWOULDBLOCK))
15940703Skarels 			error = 0;
16037728Smckusick 	cnt -= auio.uio_resid;
16137728Smckusick #ifdef KTRACE
16237728Smckusick 	if (ktriov != NULL) {
16341178Smarc 		if (error == 0)
164*68316Scgd 			ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, ktriov,
16543448Smckusick 			    cnt, error);
16637728Smckusick 		FREE(ktriov, M_TEMP);
16737728Smckusick 	}
16837728Smckusick #endif
16942922Smckusick 	*retval = cnt;
17037127Skarels done:
17152481Storek 	if (needfree)
17252481Storek 		FREE(needfree, M_IOV);
17344405Skarels 	return (error);
1747423Sroot }
1757423Sroot 
1767423Sroot /*
1777423Sroot  * Write system call
1787423Sroot  */
179*68316Scgd int
write(p,uap,retval)18042922Smckusick write(p, uap, retval)
18142922Smckusick 	struct proc *p;
182*68316Scgd 	register struct write_args /* {
183*68316Scgd 		syscallarg(int) fd;
184*68316Scgd 		syscallarg(char *) buf;
185*68316Scgd 		syscallarg(u_int) nbyte;
186*68316Scgd 	} */ *uap;
187*68316Scgd 	register_t *retval;
18842922Smckusick {
18937728Smckusick 	register struct file *fp;
19045914Smckusick 	register struct filedesc *fdp = p->p_fd;
1917820Sroot 	struct uio auio;
1927820Sroot 	struct iovec aiov;
19337728Smckusick 	long cnt, error = 0;
19437728Smckusick #ifdef KTRACE
19537728Smckusick 	struct iovec ktriov;
19637728Smckusick #endif
1977423Sroot 
198*68316Scgd 	if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
199*68316Scgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
20037728Smckusick 	    (fp->f_flag & FWRITE) == 0)
20144405Skarels 		return (EBADF);
202*68316Scgd 	aiov.iov_base = (caddr_t)SCARG(uap, buf);
203*68316Scgd 	aiov.iov_len = SCARG(uap, nbyte);
2047820Sroot 	auio.uio_iov = &aiov;
2057820Sroot 	auio.uio_iovcnt = 1;
206*68316Scgd 	auio.uio_resid = SCARG(uap, nbyte);
20737728Smckusick 	auio.uio_rw = UIO_WRITE;
20837728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
20948027Smckusick 	auio.uio_procp = p;
21037728Smckusick #ifdef KTRACE
21137728Smckusick 	/*
21237728Smckusick 	 * if tracing, save a copy of iovec
21337728Smckusick 	 */
21442922Smckusick 	if (KTRPOINT(p, KTR_GENIO))
21537728Smckusick 		ktriov = aiov;
21637728Smckusick #endif
217*68316Scgd 	cnt = SCARG(uap, nbyte);
21840703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
21940703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
22040703Skarels 		    error == EINTR || error == EWOULDBLOCK))
22140703Skarels 			error = 0;
22240703Skarels 		if (error == EPIPE)
22342922Smckusick 			psignal(p, SIGPIPE);
22440703Skarels 	}
22537728Smckusick 	cnt -= auio.uio_resid;
22637728Smckusick #ifdef KTRACE
22742922Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
228*68316Scgd 		ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
22943448Smckusick 		    &ktriov, cnt, error);
23037728Smckusick #endif
23142922Smckusick 	*retval = cnt;
23244405Skarels 	return (error);
2337820Sroot }
2347820Sroot 
23542922Smckusick /*
23642922Smckusick  * Gather write system call
23742922Smckusick  */
238*68316Scgd int
writev(p,uap,retval)23942922Smckusick writev(p, uap, retval)
24042922Smckusick 	struct proc *p;
241*68316Scgd 	register struct writev_args /* {
242*68316Scgd 		syscallarg(int) fd;
243*68316Scgd 		syscallarg(struct iovec *) iovp;
244*68316Scgd 		syscallarg(u_int) iovcnt;
245*68316Scgd 	} */ *uap;
246*68316Scgd 	register_t *retval;
24742922Smckusick {
24837728Smckusick 	register struct file *fp;
24945914Smckusick 	register struct filedesc *fdp = p->p_fd;
2507820Sroot 	struct uio auio;
25137728Smckusick 	register struct iovec *iov;
25252481Storek 	struct iovec *needfree;
25337728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
25437728Smckusick 	long i, cnt, error = 0;
25564409Sbostic 	u_int iovlen;
25637728Smckusick #ifdef KTRACE
25737728Smckusick 	struct iovec *ktriov = NULL;
25837728Smckusick #endif
2597820Sroot 
260*68316Scgd 	if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
261*68316Scgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
26237728Smckusick 	    (fp->f_flag & FWRITE) == 0)
26344405Skarels 		return (EBADF);
26444939Skarels 	/* note: can't use iovlen until iovcnt is validated */
265*68316Scgd 	iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
266*68316Scgd 	if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
267*68316Scgd 		if (SCARG(uap, iovcnt) > UIO_MAXIOV)
26844405Skarels 			return (EINVAL);
26944939Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
27052481Storek 		needfree = iov;
27152481Storek 	} else {
27237127Skarels 		iov = aiov;
27352481Storek 		needfree = NULL;
27452481Storek 	}
27537127Skarels 	auio.uio_iov = iov;
276*68316Scgd 	auio.uio_iovcnt = SCARG(uap, iovcnt);
27737728Smckusick 	auio.uio_rw = UIO_WRITE;
27837728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
27948027Smckusick 	auio.uio_procp = p;
280*68316Scgd 	if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
28137127Skarels 		goto done;
28237728Smckusick 	auio.uio_resid = 0;
283*68316Scgd 	for (i = 0; i < SCARG(uap, iovcnt); i++) {
28467491Smckusick 		if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
28537728Smckusick 			error = EINVAL;
28637728Smckusick 			goto done;
2877820Sroot 		}
28837728Smckusick 		auio.uio_resid += iov->iov_len;
28913270Ssam 		iov++;
2907820Sroot 	}
29137127Skarels #ifdef KTRACE
29237728Smckusick 	/*
29337728Smckusick 	 * if tracing, save a copy of iovec
29437728Smckusick 	 */
29542922Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
29637127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
29737728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
29837127Skarels 	}
29937127Skarels #endif
30037728Smckusick 	cnt = auio.uio_resid;
30140703Skarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
30240703Skarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
30340703Skarels 		    error == EINTR || error == EWOULDBLOCK))
30440703Skarels 			error = 0;
30540703Skarels 		if (error == EPIPE)
30642922Smckusick 			psignal(p, SIGPIPE);
30740703Skarels 	}
30837728Smckusick 	cnt -= auio.uio_resid;
30937127Skarels #ifdef KTRACE
31037127Skarels 	if (ktriov != NULL) {
31141178Smarc 		if (error == 0)
312*68316Scgd 			ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
31343448Smckusick 				ktriov, cnt, error);
31437127Skarels 		FREE(ktriov, M_TEMP);
31537127Skarels 	}
31637127Skarels #endif
31742922Smckusick 	*retval = cnt;
31837728Smckusick done:
31952481Storek 	if (needfree)
32052481Storek 		FREE(needfree, M_IOV);
32144405Skarels 	return (error);
3227423Sroot }
3237423Sroot 
3247423Sroot /*
3257423Sroot  * Ioctl system call
3267423Sroot  */
32742922Smckusick /* ARGSUSED */
328*68316Scgd int
ioctl(p,uap,retval)32942922Smckusick ioctl(p, uap, retval)
33042922Smckusick 	struct proc *p;
331*68316Scgd 	register struct ioctl_args /* {
332*68316Scgd 		syscallarg(int) fd;
333*68316Scgd 		syscallarg(u_long) com;
334*68316Scgd 		syscallarg(caddr_t) data;
335*68316Scgd 	} */ *uap;
336*68316Scgd 	register_t *retval;
33742922Smckusick {
33842922Smckusick 	register struct file *fp;
33964538Sbostic 	register struct filedesc *fdp;
340*68316Scgd 	register u_long com;
341*68316Scgd 	register int error;
3427820Sroot 	register u_int size;
34364538Sbostic 	caddr_t data, memp;
34464538Sbostic 	int tmp;
34530530Skarels #define STK_PARAMS	128
34633480Skarels 	char stkbuf[STK_PARAMS];
3477423Sroot 
34864538Sbostic 	fdp = p->p_fd;
349*68316Scgd 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
350*68316Scgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
35144405Skarels 		return (EBADF);
35264538Sbostic 
35364538Sbostic 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
35444405Skarels 		return (EBADF);
3557624Ssam 
356*68316Scgd 	switch (com = SCARG(uap, com)) {
35764538Sbostic 	case FIONCLEX:
358*68316Scgd 		fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE;
35964538Sbostic 		return (0);
36064538Sbostic 	case FIOCLEX:
361*68316Scgd 		fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
36244405Skarels 		return (0);
3637423Sroot 	}
3647624Ssam 
3657624Ssam 	/*
36664538Sbostic 	 * Interpret high order word to find amount of data to be
36764538Sbostic 	 * copied to/from the user's address space.
3687624Ssam 	 */
36930530Skarels 	size = IOCPARM_LEN(com);
37040703Skarels 	if (size > IOCPARM_MAX)
37144405Skarels 		return (ENOTTY);
37264538Sbostic 	memp = NULL;
37333480Skarels 	if (size > sizeof (stkbuf)) {
37443383Smckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
37531653Smckusick 		data = memp;
37664538Sbostic 	} else
37764538Sbostic 		data = stkbuf;
37810601Ssam 	if (com&IOC_IN) {
37910601Ssam 		if (size) {
380*68316Scgd 			error = copyin(SCARG(uap, data), data, (u_int)size);
38140703Skarels 			if (error) {
38231653Smckusick 				if (memp)
38331653Smckusick 					free(memp, M_IOCTLOPS);
38444405Skarels 				return (error);
38531653Smckusick 			}
38610601Ssam 		} else
387*68316Scgd 			*(caddr_t *)data = SCARG(uap, data);
38810601Ssam 	} else if ((com&IOC_OUT) && size)
38910601Ssam 		/*
39037127Skarels 		 * Zero the buffer so the user always
39137127Skarels 		 * gets back something deterministic.
39210601Ssam 		 */
39330530Skarels 		bzero(data, size);
39411284Ssam 	else if (com&IOC_VOID)
395*68316Scgd 		*(caddr_t *)data = SCARG(uap, data);
3967423Sroot 
39712751Ssam 	switch (com) {
3987624Ssam 
39912751Ssam 	case FIONBIO:
40048027Smckusick 		if (tmp = *(int *)data)
40149941Smckusick 			fp->f_flag |= FNONBLOCK;
40248027Smckusick 		else
40349941Smckusick 			fp->f_flag &= ~FNONBLOCK;
40448027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
40530530Skarels 		break;
40612751Ssam 
40712751Ssam 	case FIOASYNC:
40848027Smckusick 		if (tmp = *(int *)data)
40948027Smckusick 			fp->f_flag |= FASYNC;
41048027Smckusick 		else
41148027Smckusick 			fp->f_flag &= ~FASYNC;
41248027Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
41330530Skarels 		break;
41412751Ssam 
41512751Ssam 	case FIOSETOWN:
41648027Smckusick 		tmp = *(int *)data;
41748027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
41848027Smckusick 			((struct socket *)fp->f_data)->so_pgid = tmp;
41948027Smckusick 			error = 0;
42048027Smckusick 			break;
42148027Smckusick 		}
42248027Smckusick 		if (tmp <= 0) {
42348027Smckusick 			tmp = -tmp;
42448027Smckusick 		} else {
42548027Smckusick 			struct proc *p1 = pfind(tmp);
42648027Smckusick 			if (p1 == 0) {
42748027Smckusick 				error = ESRCH;
42848027Smckusick 				break;
42948027Smckusick 			}
43048027Smckusick 			tmp = p1->p_pgrp->pg_id;
43148027Smckusick 		}
43248027Smckusick 		error = (*fp->f_ops->fo_ioctl)
433*68316Scgd 			(fp, TIOCSPGRP, (caddr_t)&tmp, p);
43430530Skarels 		break;
43512751Ssam 
43612751Ssam 	case FIOGETOWN:
43748027Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
43848027Smckusick 			error = 0;
43948027Smckusick 			*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
44048027Smckusick 			break;
44148027Smckusick 		}
442*68316Scgd 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p);
44348027Smckusick 		*(int *)data = -*(int *)data;
44430530Skarels 		break;
44548027Smckusick 
44630530Skarels 	default:
44747540Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
44830530Skarels 		/*
44930530Skarels 		 * Copy any data to user, size was
45030530Skarels 		 * already set and checked above.
45130530Skarels 		 */
45240703Skarels 		if (error == 0 && (com&IOC_OUT) && size)
453*68316Scgd 			error = copyout(data, SCARG(uap, data), (u_int)size);
45430530Skarels 		break;
4557423Sroot 	}
45631653Smckusick 	if (memp)
45731653Smckusick 		free(memp, M_IOCTLOPS);
45844405Skarels 	return (error);
4597423Sroot }
4607423Sroot 
46149227Skarels int	selwait, nselcoll;
46217593Skarels 
4637423Sroot /*
46412751Ssam  * Select system call.
4657423Sroot  */
466*68316Scgd int
select(p,uap,retval)46742922Smckusick select(p, uap, retval)
46842922Smckusick 	register struct proc *p;
469*68316Scgd 	register struct select_args /* {
470*68316Scgd 		syscallarg(u_int) nd;
471*68316Scgd 		syscallarg(fd_set *) in;
472*68316Scgd 		syscallarg(fd_set *) ou;
473*68316Scgd 		syscallarg(fd_set *) ex;
474*68316Scgd 		syscallarg(struct timeval *) tv;
475*68316Scgd 	} */ *uap;
476*68316Scgd 	register_t *retval;
47742922Smckusick {
47823523Skarels 	fd_set ibits[3], obits[3];
47912751Ssam 	struct timeval atv;
48067661Smckusick 	int s, ncoll, error, timo = 0;
48163864Smckusick 	u_int ni;
48212751Ssam 
48326277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
48426277Skarels 	bzero((caddr_t)obits, sizeof(obits));
485*68316Scgd 	if (SCARG(uap, nd) > FD_SETSIZE)
48663864Smckusick 		return (EINVAL);
487*68316Scgd 	if (SCARG(uap, nd) > p->p_fd->fd_nfiles) {
488*68316Scgd 		/* forgiving; slightly wrong */
489*68316Scgd 		SCARG(uap, nd) = p->p_fd->fd_nfiles;
490*68316Scgd 	}
491*68316Scgd 	ni = howmany(SCARG(uap, nd), NFDBITS) * sizeof(fd_mask);
49212751Ssam 
49312751Ssam #define	getbits(name, x) \
494*68316Scgd 	if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, name), \
495*68316Scgd 	    (caddr_t)&ibits[x], ni))) \
49663864Smckusick 		goto done;
49712751Ssam 	getbits(in, 0);
49812751Ssam 	getbits(ou, 1);
49912751Ssam 	getbits(ex, 2);
50012751Ssam #undef	getbits
50112751Ssam 
502*68316Scgd 	if (SCARG(uap, tv)) {
503*68316Scgd 		error = copyin((caddr_t)SCARG(uap, tv), (caddr_t)&atv,
50412751Ssam 			sizeof (atv));
50540703Skarels 		if (error)
50612751Ssam 			goto done;
50712751Ssam 		if (itimerfix(&atv)) {
50840703Skarels 			error = EINVAL;
50912751Ssam 			goto done;
51012751Ssam 		}
51154760Storek 		s = splclock();
51254760Storek 		timevaladd(&atv, (struct timeval *)&time);
51354276Sbostic 		splx(s);
51467661Smckusick 	}
51512751Ssam retry:
51612751Ssam 	ncoll = nselcoll;
51764583Sbostic 	p->p_flag |= P_SELECT;
518*68316Scgd 	error = selscan(p, ibits, obits, SCARG(uap, nd), retval);
51942922Smckusick 	if (error || *retval)
52012751Ssam 		goto done;
52117934Skarels 	s = splhigh();
522*68316Scgd 	if (SCARG(uap, tv)) {
52367633Smckusick 		if (timercmp(&time, &atv, >=)) {
52467633Smckusick 			splx(s);
52567633Smckusick 			goto done;
52667633Smckusick 		}
52767633Smckusick 		/*
52867661Smckusick 		 * If poll wait was tiny, this could be zero; we will
52967661Smckusick 		 * have to round it up to avoid sleeping forever.  If
53067661Smckusick 		 * we retry below, the timercmp above will get us out.
53167661Smckusick 		 * Note that if wait was 0, the timercmp will prevent
53267661Smckusick 		 * us from getting here the first time.
53367633Smckusick 		 */
53467661Smckusick 		timo = hzto(&atv);
53567661Smckusick 		if (timo == 0)
53667633Smckusick 			timo = 1;
53712751Ssam 	}
53864583Sbostic 	if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
53912751Ssam 		splx(s);
54012751Ssam 		goto retry;
54112751Ssam 	}
54264583Sbostic 	p->p_flag &= ~P_SELECT;
54340703Skarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
54412751Ssam 	splx(s);
54540703Skarels 	if (error == 0)
54640703Skarels 		goto retry;
54712751Ssam done:
54864583Sbostic 	p->p_flag &= ~P_SELECT;
54940703Skarels 	/* select is not restarted after signals... */
55040703Skarels 	if (error == ERESTART)
55140703Skarels 		error = EINTR;
55240703Skarels 	if (error == EWOULDBLOCK)
55340703Skarels 		error = 0;
55412751Ssam #define	putbits(name, x) \
555*68316Scgd 	if (SCARG(uap, name) && (error2 = copyout((caddr_t)&obits[x], \
556*68316Scgd 	    (caddr_t)SCARG(uap, name), ni))) \
55763864Smckusick 		error = error2;
55840703Skarels 	if (error == 0) {
55963864Smckusick 		int error2;
56063864Smckusick 
56121106Skarels 		putbits(in, 0);
56221106Skarels 		putbits(ou, 1);
56321106Skarels 		putbits(ex, 2);
56412751Ssam #undef putbits
56521106Skarels 	}
56644405Skarels 	return (error);
56712751Ssam }
56812751Ssam 
569*68316Scgd int
selscan(p,ibits,obits,nfd,retval)57047540Skarels selscan(p, ibits, obits, nfd, retval)
57147540Skarels 	struct proc *p;
57223523Skarels 	fd_set *ibits, *obits;
573*68316Scgd 	int nfd;
574*68316Scgd 	register_t *retval;
57512751Ssam {
57647540Skarels 	register struct filedesc *fdp = p->p_fd;
57752481Storek 	register int msk, i, j, fd;
57823523Skarels 	register fd_mask bits;
57912751Ssam 	struct file *fp;
58052481Storek 	int n = 0;
58152481Storek 	static int flag[3] = { FREAD, FWRITE, 0 };
58212751Ssam 
58352481Storek 	for (msk = 0; msk < 3; msk++) {
58423523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
58552481Storek 			bits = ibits[msk].fds_bits[i/NFDBITS];
58652481Storek 			while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
58717593Skarels 				bits &= ~(1 << j);
58852481Storek 				fp = fdp->fd_ofiles[fd];
58952481Storek 				if (fp == NULL)
59052481Storek 					return (EBADF);
59152481Storek 				if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
59252481Storek 					FD_SET(fd, &obits[msk]);
59317593Skarels 					n++;
59417593Skarels 				}
59512751Ssam 			}
59612751Ssam 		}
59712751Ssam 	}
59842922Smckusick 	*retval = n;
59952481Storek 	return (0);
60012751Ssam }
60112751Ssam 
6027423Sroot /*ARGSUSED*/
603*68316Scgd int
seltrue(dev,flag,p)60447540Skarels seltrue(dev, flag, p)
60512751Ssam 	dev_t dev;
60612751Ssam 	int flag;
60747540Skarels 	struct proc *p;
6087423Sroot {
6097423Sroot 
61012751Ssam 	return (1);
6117423Sroot }
6128103Sroot 
61352525Smckusick /*
61452525Smckusick  * Record a select request.
61552525Smckusick  */
61652525Smckusick void
selrecord(selector,sip)61752525Smckusick selrecord(selector, sip)
61852525Smckusick 	struct proc *selector;
61952525Smckusick 	struct selinfo *sip;
6208103Sroot {
62152525Smckusick 	struct proc *p;
62252525Smckusick 	pid_t mypid;
6238103Sroot 
62452525Smckusick 	mypid = selector->p_pid;
62552525Smckusick 	if (sip->si_pid == mypid)
62652525Smckusick 		return;
62752525Smckusick 	if (sip->si_pid && (p = pfind(sip->si_pid)) &&
62852525Smckusick 	    p->p_wchan == (caddr_t)&selwait)
62952525Smckusick 		sip->si_flags |= SI_COLL;
63052525Smckusick 	else
63152525Smckusick 		sip->si_pid = mypid;
63252525Smckusick }
63352525Smckusick 
63452525Smckusick /*
63552525Smckusick  * Do a wakeup when a selectable event occurs.
63652525Smckusick  */
63752525Smckusick void
selwakeup(sip)63852525Smckusick selwakeup(sip)
63952525Smckusick 	register struct selinfo *sip;
64052525Smckusick {
64152525Smckusick 	register struct proc *p;
64252525Smckusick 	int s;
64352525Smckusick 
64452525Smckusick 	if (sip->si_pid == 0)
64552525Smckusick 		return;
64652525Smckusick 	if (sip->si_flags & SI_COLL) {
64712751Ssam 		nselcoll++;
64852525Smckusick 		sip->si_flags &= ~SI_COLL;
64912751Ssam 		wakeup((caddr_t)&selwait);
65012751Ssam 	}
65152922Smckusick 	p = pfind(sip->si_pid);
65252922Smckusick 	sip->si_pid = 0;
65352922Smckusick 	if (p != NULL) {
65452525Smckusick 		s = splhigh();
65517270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
65617270Skarels 			if (p->p_stat == SSLEEP)
65764538Sbostic 				setrunnable(p);
65817270Skarels 			else
65917270Skarels 				unsleep(p);
66064583Sbostic 		} else if (p->p_flag & P_SELECT)
66164583Sbostic 			p->p_flag &= ~P_SELECT;
66212751Ssam 		splx(s);
66312751Ssam 	}
6648103Sroot }
665