xref: /csrg-svn/sys/kern/sys_generic.c (revision 37728)
123384Smckusick /*
2*37728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3*37728Smckusick  * All rights reserved.
423384Smckusick  *
5*37728Smckusick  * Redistribution and use in source and binary forms are permitted
6*37728Smckusick  * provided that the above copyright notice and this paragraph are
7*37728Smckusick  * duplicated in all such forms and that any documentation,
8*37728Smckusick  * advertising materials, and other materials related to such
9*37728Smckusick  * distribution and use acknowledge that the software was developed
10*37728Smckusick  * by the University of California, Berkeley.  The name of the
11*37728Smckusick  * University may not be used to endorse or promote products derived
12*37728Smckusick  * from this software without specific prior written permission.
13*37728Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*37728Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*37728Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*37728Smckusick  *
17*37728Smckusick  *	@(#)sys_generic.c	7.10 (Berkeley) 05/09/89
1823384Smckusick  */
197423Sroot 
2017094Sbloom #include "param.h"
2117094Sbloom #include "systm.h"
22*37728Smckusick #include "syscontext.h"
2317094Sbloom #include "ioctl.h"
2417094Sbloom #include "file.h"
2517094Sbloom #include "proc.h"
2617094Sbloom #include "uio.h"
2717094Sbloom #include "kernel.h"
2817094Sbloom #include "stat.h"
2931653Smckusick #include "malloc.h"
3037127Skarels #ifdef KTRACE
3137127Skarels #include "ktrace.h"
3237127Skarels #endif
337423Sroot 
347423Sroot /*
357423Sroot  * Read system call.
367423Sroot  */
377423Sroot read()
387423Sroot {
397423Sroot 	register struct a {
407423Sroot 		int	fdes;
417423Sroot 		char	*cbuf;
427423Sroot 		unsigned count;
437820Sroot 	} *uap = (struct a *)u.u_ap;
44*37728Smckusick 	register struct file *fp;
457746Sroot 	struct uio auio;
467746Sroot 	struct iovec aiov;
47*37728Smckusick 	long cnt, error = 0;
48*37728Smckusick #ifdef KTRACE
49*37728Smckusick 	struct iovec ktriov;
50*37728Smckusick #endif
517423Sroot 
52*37728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
53*37728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
54*37728Smckusick 	    (fp->f_flag & FREAD) == 0)
55*37728Smckusick 		RETURN (EBADF);
56*37728Smckusick 	if (uap->count < 0)
57*37728Smckusick 		RETURN (EINVAL);
587820Sroot 	aiov.iov_base = (caddr_t)uap->cbuf;
597820Sroot 	aiov.iov_len = uap->count;
607820Sroot 	auio.uio_iov = &aiov;
617820Sroot 	auio.uio_iovcnt = 1;
62*37728Smckusick 	auio.uio_resid = uap->count;
63*37728Smckusick 	auio.uio_rw = UIO_READ;
64*37728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
65*37728Smckusick #ifdef KTRACE
66*37728Smckusick 	/*
67*37728Smckusick 	 * if tracing, save a copy of iovec
68*37728Smckusick 	 */
69*37728Smckusick 	if (KTRPOINT(u.u_procp, KTR_GENIO))
70*37728Smckusick 		ktriov = aiov;
71*37728Smckusick #endif
72*37728Smckusick 	cnt = uap->count;
73*37728Smckusick 	if (setjmp(&u.u_qsave)) {
74*37728Smckusick 		if (auio.uio_resid == cnt) {
75*37728Smckusick 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
76*37728Smckusick 				error = EINTR;
77*37728Smckusick 			else
78*37728Smckusick 				u.u_eosys = RESTARTSYS;
79*37728Smckusick 		}
80*37728Smckusick 	} else
81*37728Smckusick 		error = (*fp->f_ops->fo_read)(fp, &auio, u.u_cred);
82*37728Smckusick 	cnt -= auio.uio_resid;
83*37728Smckusick #ifdef KTRACE
84*37728Smckusick 	if (KTRPOINT(u.u_procp, KTR_GENIO))
85*37728Smckusick 		ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_READ, ktriov, cnt);
86*37728Smckusick #endif
87*37728Smckusick 	u.u_r.r_val1 = cnt;
88*37728Smckusick 	RETURN (error);
897820Sroot }
907820Sroot 
917820Sroot readv()
927820Sroot {
937820Sroot 	register struct a {
947820Sroot 		int	fdes;
957820Sroot 		struct	iovec *iovp;
9626474Skarels 		unsigned iovcnt;
977820Sroot 	} *uap = (struct a *)u.u_ap;
98*37728Smckusick 	register struct file *fp;
997820Sroot 	struct uio auio;
100*37728Smckusick 	register struct iovec *iov;
101*37728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
102*37728Smckusick 	long i, cnt, error = 0;
103*37728Smckusick #ifdef KTRACE
104*37728Smckusick 	struct iovec *ktriov = NULL;
105*37728Smckusick #endif
1067820Sroot 
107*37728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
108*37728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
109*37728Smckusick 	    (fp->f_flag & FREAD) == 0)
110*37728Smckusick 		RETURN (EBADF);
11137127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
112*37728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
113*37728Smckusick 			RETURN (EINVAL);
11437127Skarels 		MALLOC(iov, struct iovec *,
11537127Skarels 		      sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
11637127Skarels 	} else
11737127Skarels 		iov = aiov;
11837127Skarels 	auio.uio_iov = iov;
1197820Sroot 	auio.uio_iovcnt = uap->iovcnt;
120*37728Smckusick 	auio.uio_rw = UIO_READ;
121*37728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
122*37728Smckusick 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
123*37728Smckusick 	    uap->iovcnt * sizeof (struct iovec)))
12437127Skarels 		goto done;
125*37728Smckusick 	auio.uio_resid = 0;
126*37728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
127*37728Smckusick 		if (iov->iov_len < 0) {
128*37728Smckusick 			error = EINVAL;
129*37728Smckusick 			goto done;
130*37728Smckusick 		}
131*37728Smckusick 		auio.uio_resid += iov->iov_len;
132*37728Smckusick 		if (auio.uio_resid < 0) {
133*37728Smckusick 			error = EINVAL;
134*37728Smckusick 			goto done;
135*37728Smckusick 		}
136*37728Smckusick 		iov++;
137*37728Smckusick 	}
138*37728Smckusick #ifdef KTRACE
139*37728Smckusick 	/*
140*37728Smckusick 	 * if tracing, save a copy of iovec
141*37728Smckusick 	 */
142*37728Smckusick 	if (KTRPOINT(u.u_procp, KTR_GENIO))  {
143*37728Smckusick 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
144*37728Smckusick 
145*37728Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
146*37728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
147*37728Smckusick 	}
148*37728Smckusick #endif
149*37728Smckusick 	cnt = auio.uio_resid;
150*37728Smckusick 	if (setjmp(&u.u_qsave)) {
151*37728Smckusick 		if (auio.uio_resid == cnt) {
152*37728Smckusick 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
153*37728Smckusick 				error = EINTR;
154*37728Smckusick 			else
155*37728Smckusick 				u.u_eosys = RESTARTSYS;
156*37728Smckusick 		}
157*37728Smckusick 	} else
158*37728Smckusick 		error = (*fp->f_ops->fo_read)(fp, &auio, u.u_cred);
159*37728Smckusick 	cnt -= auio.uio_resid;
160*37728Smckusick #ifdef KTRACE
161*37728Smckusick 	if (ktriov != NULL) {
162*37728Smckusick 		ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_READ, ktriov, cnt);
163*37728Smckusick 		FREE(ktriov, M_TEMP);
164*37728Smckusick 	}
165*37728Smckusick #endif
166*37728Smckusick 	u.u_r.r_val1 = cnt;
16737127Skarels done:
168*37728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
16937127Skarels 		FREE(iov, M_IOV);
170*37728Smckusick 	RETURN (error);
1717423Sroot }
1727423Sroot 
1737423Sroot /*
1747423Sroot  * Write system call
1757423Sroot  */
1767423Sroot write()
1777423Sroot {
1787423Sroot 	register struct a {
1797423Sroot 		int	fdes;
1807423Sroot 		char	*cbuf;
18126474Skarels 		unsigned count;
1827820Sroot 	} *uap = (struct a *)u.u_ap;
183*37728Smckusick 	register struct file *fp;
1847820Sroot 	struct uio auio;
1857820Sroot 	struct iovec aiov;
186*37728Smckusick 	long cnt, error = 0;
187*37728Smckusick #ifdef KTRACE
188*37728Smckusick 	struct iovec ktriov;
189*37728Smckusick #endif
1907423Sroot 
191*37728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
192*37728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
193*37728Smckusick 	    (fp->f_flag & FWRITE) == 0)
194*37728Smckusick 		RETURN (EBADF);
195*37728Smckusick 	if (uap->count < 0)
196*37728Smckusick 		RETURN (EINVAL);
197*37728Smckusick 	aiov.iov_base = (caddr_t)uap->cbuf;
198*37728Smckusick 	aiov.iov_len = uap->count;
1997820Sroot 	auio.uio_iov = &aiov;
2007820Sroot 	auio.uio_iovcnt = 1;
201*37728Smckusick 	auio.uio_resid = uap->count;
202*37728Smckusick 	auio.uio_rw = UIO_WRITE;
203*37728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
204*37728Smckusick #ifdef KTRACE
205*37728Smckusick 	/*
206*37728Smckusick 	 * if tracing, save a copy of iovec
207*37728Smckusick 	 */
208*37728Smckusick 	if (KTRPOINT(u.u_procp, KTR_GENIO))
209*37728Smckusick 		ktriov = aiov;
210*37728Smckusick #endif
211*37728Smckusick 	cnt = uap->count;
212*37728Smckusick 	if (setjmp(&u.u_qsave)) {
213*37728Smckusick 		if (auio.uio_resid == cnt) {
214*37728Smckusick 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
215*37728Smckusick 				error = EINTR;
216*37728Smckusick 			else
217*37728Smckusick 				u.u_eosys = RESTARTSYS;
218*37728Smckusick 		}
219*37728Smckusick 	} else
220*37728Smckusick 		error = (*fp->f_ops->fo_write)(fp, &auio, u.u_cred);
221*37728Smckusick 	cnt -= auio.uio_resid;
222*37728Smckusick #ifdef KTRACE
223*37728Smckusick 	if (KTRPOINT(u.u_procp, KTR_GENIO))
224*37728Smckusick 		ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_WRITE,
225*37728Smckusick 		    ktriov, cnt);
226*37728Smckusick #endif
227*37728Smckusick 	u.u_r.r_val1 = cnt;
228*37728Smckusick 	RETURN (error);
2297820Sroot }
2307820Sroot 
2317820Sroot writev()
2327820Sroot {
2337820Sroot 	register struct a {
2347820Sroot 		int	fdes;
2357820Sroot 		struct	iovec *iovp;
23626474Skarels 		unsigned iovcnt;
2377820Sroot 	} *uap = (struct a *)u.u_ap;
238*37728Smckusick 	register struct file *fp;
2397820Sroot 	struct uio auio;
240*37728Smckusick 	register struct iovec *iov;
241*37728Smckusick 	struct iovec aiov[UIO_SMALLIOV];
242*37728Smckusick 	long i, cnt, error = 0;
243*37728Smckusick #ifdef KTRACE
244*37728Smckusick 	struct iovec *ktriov = NULL;
245*37728Smckusick #endif
2467820Sroot 
247*37728Smckusick 	if (((unsigned)uap->fdes) >= NOFILE ||
248*37728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL ||
249*37728Smckusick 	    (fp->f_flag & FWRITE) == 0)
250*37728Smckusick 		RETURN (EBADF);
25137127Skarels 	if (uap->iovcnt > UIO_SMALLIOV) {
252*37728Smckusick 		if (uap->iovcnt > UIO_MAXIOV)
253*37728Smckusick 			RETURN (EINVAL);
25437127Skarels 		MALLOC(iov, struct iovec *,
25537127Skarels 		      sizeof(struct iovec) * uap->iovcnt, M_IOV, M_WAITOK);
25637127Skarels 	} else
25737127Skarels 		iov = aiov;
25837127Skarels 	auio.uio_iov = iov;
2597820Sroot 	auio.uio_iovcnt = uap->iovcnt;
260*37728Smckusick 	auio.uio_rw = UIO_WRITE;
261*37728Smckusick 	auio.uio_segflg = UIO_USERSPACE;
262*37728Smckusick 	if (error = copyin((caddr_t)uap->iovp, (caddr_t)iov,
263*37728Smckusick 	    uap->iovcnt * sizeof (struct iovec)))
26437127Skarels 		goto done;
265*37728Smckusick 	auio.uio_resid = 0;
266*37728Smckusick 	for (i = 0; i < uap->iovcnt; i++) {
2677820Sroot 		if (iov->iov_len < 0) {
268*37728Smckusick 			error = EINVAL;
269*37728Smckusick 			goto done;
2707820Sroot 		}
271*37728Smckusick 		auio.uio_resid += iov->iov_len;
272*37728Smckusick 		if (auio.uio_resid < 0) {
273*37728Smckusick 			error = EINVAL;
274*37728Smckusick 			goto done;
2757820Sroot 		}
27613270Ssam 		iov++;
2777820Sroot 	}
27837127Skarels #ifdef KTRACE
279*37728Smckusick 	/*
280*37728Smckusick 	 * if tracing, save a copy of iovec
281*37728Smckusick 	 */
28237127Skarels 	if (KTRPOINT(u.u_procp, KTR_GENIO))  {
283*37728Smckusick 		int iovlen = auio.uio_iovcnt * sizeof (struct iovec);
28437127Skarels 
28537127Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
286*37728Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
28737127Skarels 	}
28837127Skarels #endif
289*37728Smckusick 	cnt = auio.uio_resid;
29018309Smckusick 	if (setjmp(&u.u_qsave)) {
291*37728Smckusick 		if (auio.uio_resid == cnt) {
29221009Smckusick 			if ((u.u_sigintr & sigmask(u.u_procp->p_cursig)) != 0)
293*37728Smckusick 				error = EINTR;
29418309Smckusick 			else
29518309Smckusick 				u.u_eosys = RESTARTSYS;
29618309Smckusick 		}
29712751Ssam 	} else
298*37728Smckusick 		error = (*fp->f_ops->fo_write)(fp, &auio, u.u_cred);
299*37728Smckusick 	cnt -= auio.uio_resid;
30037127Skarels #ifdef KTRACE
30137127Skarels 	if (ktriov != NULL) {
302*37728Smckusick 		ktrgenio(u.u_procp->p_tracep, uap->fdes, UIO_WRITE,
303*37728Smckusick 		    ktriov, cnt);
30437127Skarels 		FREE(ktriov, M_TEMP);
30537127Skarels 	}
30637127Skarels #endif
307*37728Smckusick 	u.u_r.r_val1 = cnt;
308*37728Smckusick done:
309*37728Smckusick 	if (uap->iovcnt > UIO_SMALLIOV)
310*37728Smckusick 		FREE(iov, M_IOV);
311*37728Smckusick 	RETURN (error);
3127423Sroot }
3137423Sroot 
3147423Sroot /*
3157423Sroot  * Ioctl system call
3167423Sroot  */
3177423Sroot ioctl()
3187423Sroot {
3197423Sroot 	register struct file *fp;
3207624Ssam 	struct a {
3217423Sroot 		int	fdes;
3227423Sroot 		int	cmd;
3237423Sroot 		caddr_t	cmarg;
324*37728Smckusick 	} *uap = (struct a *)u.u_ap;
3257820Sroot 	register int com;
3267820Sroot 	register u_int size;
32731653Smckusick 	caddr_t memp = 0;
32830530Skarels #define STK_PARAMS	128
32933480Skarels 	char stkbuf[STK_PARAMS];
33033480Skarels 	caddr_t data = stkbuf;
3317423Sroot 
332*37728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
333*37728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
334*37728Smckusick 		RETURN (EBADF);
3357423Sroot 	if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
3367423Sroot 		u.u_error = EBADF;
3377423Sroot 		return;
3387423Sroot 	}
3397624Ssam 	com = uap->cmd;
3407624Ssam 
3417624Ssam 	if (com == FIOCLEX) {
3429592Ssam 		u.u_pofile[uap->fdes] |= UF_EXCLOSE;
3437423Sroot 		return;
3447423Sroot 	}
3457624Ssam 	if (com == FIONCLEX) {
3469592Ssam 		u.u_pofile[uap->fdes] &= ~UF_EXCLOSE;
3477423Sroot 		return;
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);
35630530Skarels 	if (size > IOCPARM_MAX) {
35737127Skarels 		u.u_error = ENOTTY;
3587423Sroot 		return;
3597423Sroot 	}
36033480Skarels 	if (size > sizeof (stkbuf)) {
36137127Skarels 		memp = (caddr_t)malloc((u_long)IOCPARM_LEN(com), M_IOCTLOPS,
36234473Smckusick 		    M_WAITOK);
36331653Smckusick 		data = memp;
36430530Skarels 	}
36510601Ssam 	if (com&IOC_IN) {
36610601Ssam 		if (size) {
36737127Skarels 			u.u_error = copyin(uap->cmarg, data, (u_int)size);
36831653Smckusick 			if (u.u_error) {
36931653Smckusick 				if (memp)
37031653Smckusick 					free(memp, M_IOCTLOPS);
37110601Ssam 				return;
37231653Smckusick 			}
37310601Ssam 		} else
37410601Ssam 			*(caddr_t *)data = uap->cmarg;
37510601Ssam 	} else if ((com&IOC_OUT) && size)
37610601Ssam 		/*
37737127Skarels 		 * Zero the buffer so the user always
37837127Skarels 		 * gets back something deterministic.
37910601Ssam 		 */
38030530Skarels 		bzero(data, size);
38111284Ssam 	else if (com&IOC_VOID)
38211284Ssam 		*(caddr_t *)data = uap->cmarg;
3837423Sroot 
38412751Ssam 	switch (com) {
3857624Ssam 
38612751Ssam 	case FIONBIO:
38712751Ssam 		u.u_error = fset(fp, FNDELAY, *(int *)data);
38830530Skarels 		break;
38912751Ssam 
39012751Ssam 	case FIOASYNC:
39112751Ssam 		u.u_error = fset(fp, FASYNC, *(int *)data);
39230530Skarels 		break;
39312751Ssam 
39412751Ssam 	case FIOSETOWN:
39512751Ssam 		u.u_error = fsetown(fp, *(int *)data);
39630530Skarels 		break;
39712751Ssam 
39812751Ssam 	case FIOGETOWN:
39912751Ssam 		u.u_error = fgetown(fp, (int *)data);
40030530Skarels 		break;
40130530Skarels 	default:
40230530Skarels 		if (setjmp(&u.u_qsave))
40330530Skarels 			u.u_error = EINTR;
40430530Skarels 		else
40530530Skarels 			u.u_error = (*fp->f_ops->fo_ioctl)(fp, com, data);
40630530Skarels 		/*
40730530Skarels 		 * Copy any data to user, size was
40830530Skarels 		 * already set and checked above.
40930530Skarels 		 */
41030530Skarels 		if (u.u_error == 0 && (com&IOC_OUT) && size)
41130530Skarels 			u.u_error = copyout(data, uap->cmarg, (u_int)size);
41230530Skarels 		break;
4137423Sroot 	}
41431653Smckusick 	if (memp)
41531653Smckusick 		free(memp, M_IOCTLOPS);
4167423Sroot }
4177423Sroot 
41812751Ssam int	unselect();
41912751Ssam int	nselcoll;
42017593Skarels 
4217423Sroot /*
42212751Ssam  * Select system call.
4237423Sroot  */
42412751Ssam select()
42512751Ssam {
42612751Ssam 	register struct uap  {
42712751Ssam 		int	nd;
42823523Skarels 		fd_set	*in, *ou, *ex;
42912751Ssam 		struct	timeval *tv;
43012751Ssam 	} *uap = (struct uap *)u.u_ap;
43123523Skarels 	fd_set ibits[3], obits[3];
43212751Ssam 	struct timeval atv;
43317593Skarels 	int s, ncoll, ni;
43412751Ssam 	label_t lqsave;
43512751Ssam 
43626277Skarels 	bzero((caddr_t)ibits, sizeof(ibits));
43726277Skarels 	bzero((caddr_t)obits, sizeof(obits));
43812751Ssam 	if (uap->nd > NOFILE)
43912751Ssam 		uap->nd = NOFILE;	/* forgiving, if slightly wrong */
44023523Skarels 	ni = howmany(uap->nd, NFDBITS);
44112751Ssam 
44212751Ssam #define	getbits(name, x) \
44312751Ssam 	if (uap->name) { \
44423523Skarels 		u.u_error = copyin((caddr_t)uap->name, (caddr_t)&ibits[x], \
44526277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
44612751Ssam 		if (u.u_error) \
44712751Ssam 			goto done; \
44817593Skarels 	}
44912751Ssam 	getbits(in, 0);
45012751Ssam 	getbits(ou, 1);
45112751Ssam 	getbits(ex, 2);
45212751Ssam #undef	getbits
45312751Ssam 
45412751Ssam 	if (uap->tv) {
45512751Ssam 		u.u_error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
45612751Ssam 			sizeof (atv));
45712751Ssam 		if (u.u_error)
45812751Ssam 			goto done;
45912751Ssam 		if (itimerfix(&atv)) {
46012751Ssam 			u.u_error = EINVAL;
46112751Ssam 			goto done;
46212751Ssam 		}
46317934Skarels 		s = splhigh(); timevaladd(&atv, &time); splx(s);
46412751Ssam 	}
46512751Ssam retry:
46612751Ssam 	ncoll = nselcoll;
46712751Ssam 	u.u_procp->p_flag |= SSEL;
46817593Skarels 	u.u_r.r_val1 = selscan(ibits, obits, uap->nd);
46912751Ssam 	if (u.u_error || u.u_r.r_val1)
47012751Ssam 		goto done;
47117934Skarels 	s = splhigh();
47212971Ssam 	/* this should be timercmp(&time, &atv, >=) */
47312971Ssam 	if (uap->tv && (time.tv_sec > atv.tv_sec ||
47412971Ssam 	    time.tv_sec == atv.tv_sec && time.tv_usec >= atv.tv_usec)) {
47512751Ssam 		splx(s);
47612751Ssam 		goto done;
47712751Ssam 	}
47812751Ssam 	if ((u.u_procp->p_flag & SSEL) == 0 || nselcoll != ncoll) {
47912751Ssam 		splx(s);
48012751Ssam 		goto retry;
48112751Ssam 	}
48212751Ssam 	u.u_procp->p_flag &= ~SSEL;
48312751Ssam 	if (uap->tv) {
48412751Ssam 		lqsave = u.u_qsave;
48512751Ssam 		if (setjmp(&u.u_qsave)) {
48612751Ssam 			untimeout(unselect, (caddr_t)u.u_procp);
48712751Ssam 			u.u_error = EINTR;
48812751Ssam 			splx(s);
48912751Ssam 			goto done;
49012751Ssam 		}
49112751Ssam 		timeout(unselect, (caddr_t)u.u_procp, hzto(&atv));
49212751Ssam 	}
49312751Ssam 	sleep((caddr_t)&selwait, PZERO+1);
49412751Ssam 	if (uap->tv) {
49512751Ssam 		u.u_qsave = lqsave;
49612751Ssam 		untimeout(unselect, (caddr_t)u.u_procp);
49712751Ssam 	}
49812751Ssam 	splx(s);
49912751Ssam 	goto retry;
50012751Ssam done:
50133712Skarels 	u.u_procp->p_flag &= ~SSEL;
50212751Ssam #define	putbits(name, x) \
50312751Ssam 	if (uap->name) { \
50423523Skarels 		int error = copyout((caddr_t)&obits[x], (caddr_t)uap->name, \
50526277Skarels 		    (unsigned)(ni * sizeof(fd_mask))); \
50612751Ssam 		if (error) \
50712751Ssam 			u.u_error = error; \
50812751Ssam 	}
50926070Skarels 	if (u.u_error == 0) {
51021106Skarels 		putbits(in, 0);
51121106Skarels 		putbits(ou, 1);
51221106Skarels 		putbits(ex, 2);
51312751Ssam #undef putbits
51421106Skarels 	}
51512751Ssam }
51612751Ssam 
51712751Ssam unselect(p)
51812751Ssam 	register struct proc *p;
51912751Ssam {
52017934Skarels 	register int s = splhigh();
52112751Ssam 
52212751Ssam 	switch (p->p_stat) {
52312751Ssam 
52412751Ssam 	case SSLEEP:
52512751Ssam 		setrun(p);
52612751Ssam 		break;
52712751Ssam 
52812751Ssam 	case SSTOP:
52912751Ssam 		unsleep(p);
53012751Ssam 		break;
53112751Ssam 	}
53212751Ssam 	splx(s);
53312751Ssam }
53412751Ssam 
53517593Skarels selscan(ibits, obits, nfd)
53623523Skarels 	fd_set *ibits, *obits;
53712751Ssam {
53823523Skarels 	register int which, i, j;
53923523Skarels 	register fd_mask bits;
54012751Ssam 	int flag;
54112751Ssam 	struct file *fp;
54212751Ssam 	int n = 0;
54312751Ssam 
54412751Ssam 	for (which = 0; which < 3; which++) {
54512751Ssam 		switch (which) {
54612751Ssam 
54712751Ssam 		case 0:
54812751Ssam 			flag = FREAD; break;
54912751Ssam 
55012751Ssam 		case 1:
55112751Ssam 			flag = FWRITE; break;
55212751Ssam 
55312751Ssam 		case 2:
55412751Ssam 			flag = 0; break;
55512751Ssam 		}
55623523Skarels 		for (i = 0; i < nfd; i += NFDBITS) {
55723523Skarels 			bits = ibits[which].fds_bits[i/NFDBITS];
55817593Skarels 			while ((j = ffs(bits)) && i + --j < nfd) {
55917593Skarels 				bits &= ~(1 << j);
56017593Skarels 				fp = u.u_ofile[i + j];
56117593Skarels 				if (fp == NULL) {
56217593Skarels 					u.u_error = EBADF;
56317593Skarels 					break;
56417593Skarels 				}
56517593Skarels 				if ((*fp->f_ops->fo_select)(fp, flag)) {
56623523Skarels 					FD_SET(i + j, &obits[which]);
56717593Skarels 					n++;
56817593Skarels 				}
56912751Ssam 			}
57012751Ssam 		}
57112751Ssam 	}
57212751Ssam 	return (n);
57312751Ssam }
57412751Ssam 
5757423Sroot /*ARGSUSED*/
57612751Ssam seltrue(dev, flag)
57712751Ssam 	dev_t dev;
57812751Ssam 	int flag;
5797423Sroot {
5807423Sroot 
58112751Ssam 	return (1);
5827423Sroot }
5838103Sroot 
58412751Ssam selwakeup(p, coll)
58512751Ssam 	register struct proc *p;
58612751Ssam 	int coll;
5878103Sroot {
5888103Sroot 
58912751Ssam 	if (coll) {
59012751Ssam 		nselcoll++;
59112751Ssam 		wakeup((caddr_t)&selwait);
59212751Ssam 	}
59312751Ssam 	if (p) {
59417934Skarels 		int s = splhigh();
59517270Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
59617270Skarels 			if (p->p_stat == SSLEEP)
59717270Skarels 				setrun(p);
59817270Skarels 			else
59917270Skarels 				unsleep(p);
60017270Skarels 		} else if (p->p_flag & SSEL)
60112751Ssam 			p->p_flag &= ~SSEL;
60212751Ssam 		splx(s);
60312751Ssam 	}
6048103Sroot }
605