xref: /original-bsd/sys/kern/sys_generic.c (revision 00487f8c)
124cbf5f8Smckusick /*
227a38ea8Sbostic  * Copyright (c) 1982, 1986, 1989, 1993
327a38ea8Sbostic  *	The Regents of the University of California.  All rights reserved.
4342da129Sbostic  * (c) UNIX System Laboratories, Inc.
5342da129Sbostic  * All or some portions of this file are derived from material licensed
6342da129Sbostic  * to the University of California by American Telephone and Telegraph
7342da129Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8342da129Sbostic  * the permission of UNIX System Laboratories, Inc.
924cbf5f8Smckusick  *
108bdc900fSbostic  * %sccs.include.redist.c%
1195d9d7e5Smckusick  *
12*00487f8cScgd  *	@(#)sys_generic.c	8.9 (Berkeley) 02/14/95
1324cbf5f8Smckusick  */
14c767fa90Sroot 
156e23d7a0Sbostic #include <sys/param.h>
166e23d7a0Sbostic #include <sys/systm.h>
176e23d7a0Sbostic #include <sys/filedesc.h>
186e23d7a0Sbostic #include <sys/ioctl.h>
196e23d7a0Sbostic #include <sys/file.h>
206e23d7a0Sbostic #include <sys/proc.h>
216e23d7a0Sbostic #include <sys/socketvar.h>
226e23d7a0Sbostic #include <sys/uio.h>
236e23d7a0Sbostic #include <sys/kernel.h>
246e23d7a0Sbostic #include <sys/stat.h>
256e23d7a0Sbostic #include <sys/malloc.h>
26a2967617Skarels #ifdef KTRACE
276e23d7a0Sbostic #include <sys/ktrace.h>
28a2967617Skarels #endif
29c767fa90Sroot 
30*00487f8cScgd #include <sys/mount.h>
31*00487f8cScgd #include <sys/syscallargs.h>
32*00487f8cScgd 
33c767fa90Sroot /*
34c767fa90Sroot  * Read system call.
35c767fa90Sroot  */
3641982c2cStorek /* ARGSUSED */
37*00487f8cScgd int
read(p,uap,retval)3841982c2cStorek read(p, uap, retval)
3941982c2cStorek 	struct proc *p;
40*00487f8cScgd 	register struct read_args /* {
41*00487f8cScgd 		syscallarg(int) fd;
42*00487f8cScgd 		syscallarg(char *) buf;
43*00487f8cScgd 		syscallarg(u_int) nbyte;
44*00487f8cScgd 	} */ *uap;
45*00487f8cScgd 	register_t *retval;
4687836a50Smckusick {
4795d9d7e5Smckusick 	register struct file *fp;
48bcf289b6Smckusick 	register struct filedesc *fdp = p->p_fd;
495a55292bSroot 	struct uio auio;
505a55292bSroot 	struct iovec aiov;
5195d9d7e5Smckusick 	long cnt, error = 0;
5295d9d7e5Smckusick #ifdef KTRACE
5395d9d7e5Smckusick 	struct iovec ktriov;
5495d9d7e5Smckusick #endif
55c767fa90Sroot 
56*00487f8cScgd 	if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
57*00487f8cScgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
5895d9d7e5Smckusick 	    (fp->f_flag & FREAD) == 0)
592c51c3e4Skarels 		return (EBADF);
60*00487f8cScgd 	aiov.iov_base = (caddr_t)SCARG(uap, buf);
61*00487f8cScgd 	aiov.iov_len = SCARG(uap, nbyte);
625a55292bSroot 	auio.uio_iov = &aiov;
635a55292bSroot 	auio.uio_iovcnt = 1;
64*00487f8cScgd 	auio.uio_resid = SCARG(uap, nbyte);
6595d9d7e5Smckusick 	auio.uio_rw = UIO_READ;
6695d9d7e5Smckusick 	auio.uio_segflg = UIO_USERSPACE;
6737dd6451Smckusick 	auio.uio_procp = p;
6895d9d7e5Smckusick #ifdef KTRACE
6995d9d7e5Smckusick 	/*
7095d9d7e5Smckusick 	 * if tracing, save a copy of iovec
7195d9d7e5Smckusick 	 */
7287836a50Smckusick 	if (KTRPOINT(p, KTR_GENIO))
7395d9d7e5Smckusick 		ktriov = aiov;
7495d9d7e5Smckusick #endif
75*00487f8cScgd 	cnt = SCARG(uap, nbyte);
76458b3cedSkarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
77458b3cedSkarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
78458b3cedSkarels 		    error == EINTR || error == EWOULDBLOCK))
79458b3cedSkarels 			error = 0;
8095d9d7e5Smckusick 	cnt -= auio.uio_resid;
8195d9d7e5Smckusick #ifdef KTRACE
8287836a50Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
83*00487f8cScgd 		ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, &ktriov,
84*00487f8cScgd 		    cnt, error);
8595d9d7e5Smckusick #endif
8687836a50Smckusick 	*retval = cnt;
872c51c3e4Skarels 	return (error);
88c767fa90Sroot }
89d5ddeb04Sroot 
9087836a50Smckusick /*
9187836a50Smckusick  * Scatter read system call.
9287836a50Smckusick  */
93*00487f8cScgd int
readv(p,uap,retval)9441982c2cStorek readv(p, uap, retval)
9541982c2cStorek 	struct proc *p;
96*00487f8cScgd 	register struct readv_args /* {
97*00487f8cScgd 		syscallarg(int) fd;
98*00487f8cScgd 		syscallarg(struct iovec *) iovp;
99*00487f8cScgd 		syscallarg(u_int) iovcnt;
100*00487f8cScgd 	} */ *uap;
101*00487f8cScgd 	register_t *retval;
10287836a50Smckusick {
10395d9d7e5Smckusick 	register struct file *fp;
104bcf289b6Smckusick 	register struct filedesc *fdp = p->p_fd;
105d5ddeb04Sroot 	struct uio auio;
10695d9d7e5Smckusick 	register struct iovec *iov;
1076b756a40Storek 	struct iovec *needfree;
10895d9d7e5Smckusick 	struct iovec aiov[UIO_SMALLIOV];
10995d9d7e5Smckusick 	long i, cnt, error = 0;
11040bd33f9Sbostic 	u_int iovlen;
11195d9d7e5Smckusick #ifdef KTRACE
11295d9d7e5Smckusick 	struct iovec *ktriov = NULL;
11395d9d7e5Smckusick #endif
114d5ddeb04Sroot 
115*00487f8cScgd 	if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
116*00487f8cScgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
11795d9d7e5Smckusick 	    (fp->f_flag & FREAD) == 0)
1182c51c3e4Skarels 		return (EBADF);
11939481ef4Skarels 	/* note: can't use iovlen until iovcnt is validated */
120*00487f8cScgd 	iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
121*00487f8cScgd 	if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
122*00487f8cScgd 		if (SCARG(uap, iovcnt) > UIO_MAXIOV)
1232c51c3e4Skarels 			return (EINVAL);
12439481ef4Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
1256b756a40Storek 		needfree = iov;
1266b756a40Storek 	} else {
127a2967617Skarels 		iov = aiov;
1286b756a40Storek 		needfree = NULL;
1296b756a40Storek 	}
130a2967617Skarels 	auio.uio_iov = iov;
131*00487f8cScgd 	auio.uio_iovcnt = SCARG(uap, iovcnt);
13295d9d7e5Smckusick 	auio.uio_rw = UIO_READ;
13395d9d7e5Smckusick 	auio.uio_segflg = UIO_USERSPACE;
13437dd6451Smckusick 	auio.uio_procp = p;
135*00487f8cScgd 	if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
136a2967617Skarels 		goto done;
13795d9d7e5Smckusick 	auio.uio_resid = 0;
138*00487f8cScgd 	for (i = 0; i < SCARG(uap, iovcnt); i++) {
139b3c14c05Smckusick 		if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
14095d9d7e5Smckusick 			error = EINVAL;
14195d9d7e5Smckusick 			goto done;
14295d9d7e5Smckusick 		}
14395d9d7e5Smckusick 		auio.uio_resid += iov->iov_len;
14495d9d7e5Smckusick 		iov++;
14595d9d7e5Smckusick 	}
14695d9d7e5Smckusick #ifdef KTRACE
14795d9d7e5Smckusick 	/*
14895d9d7e5Smckusick 	 * if tracing, save a copy of iovec
14995d9d7e5Smckusick 	 */
15087836a50Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
15195d9d7e5Smckusick 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
15295d9d7e5Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
15395d9d7e5Smckusick 	}
15495d9d7e5Smckusick #endif
15595d9d7e5Smckusick 	cnt = auio.uio_resid;
156458b3cedSkarels 	if (error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred))
157458b3cedSkarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
158458b3cedSkarels 		    error == EINTR || error == EWOULDBLOCK))
159458b3cedSkarels 			error = 0;
16095d9d7e5Smckusick 	cnt -= auio.uio_resid;
16195d9d7e5Smckusick #ifdef KTRACE
16295d9d7e5Smckusick 	if (ktriov != NULL) {
163817fcec3Smarc 		if (error == 0)
164*00487f8cScgd 			ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_READ, ktriov,
165ee209021Smckusick 			    cnt, error);
16695d9d7e5Smckusick 		FREE(ktriov, M_TEMP);
16795d9d7e5Smckusick 	}
16895d9d7e5Smckusick #endif
16987836a50Smckusick 	*retval = cnt;
170a2967617Skarels done:
1716b756a40Storek 	if (needfree)
1726b756a40Storek 		FREE(needfree, M_IOV);
1732c51c3e4Skarels 	return (error);
174c767fa90Sroot }
175c767fa90Sroot 
176c767fa90Sroot /*
177c767fa90Sroot  * Write system call
178c767fa90Sroot  */
179*00487f8cScgd int
write(p,uap,retval)18041982c2cStorek write(p, uap, retval)
18141982c2cStorek 	struct proc *p;
182*00487f8cScgd 	register struct write_args /* {
183*00487f8cScgd 		syscallarg(int) fd;
184*00487f8cScgd 		syscallarg(char *) buf;
185*00487f8cScgd 		syscallarg(u_int) nbyte;
186*00487f8cScgd 	} */ *uap;
187*00487f8cScgd 	register_t *retval;
18887836a50Smckusick {
18995d9d7e5Smckusick 	register struct file *fp;
190bcf289b6Smckusick 	register struct filedesc *fdp = p->p_fd;
191d5ddeb04Sroot 	struct uio auio;
192d5ddeb04Sroot 	struct iovec aiov;
19395d9d7e5Smckusick 	long cnt, error = 0;
19495d9d7e5Smckusick #ifdef KTRACE
19595d9d7e5Smckusick 	struct iovec ktriov;
19695d9d7e5Smckusick #endif
197c767fa90Sroot 
198*00487f8cScgd 	if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
199*00487f8cScgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
20095d9d7e5Smckusick 	    (fp->f_flag & FWRITE) == 0)
2012c51c3e4Skarels 		return (EBADF);
202*00487f8cScgd 	aiov.iov_base = (caddr_t)SCARG(uap, buf);
203*00487f8cScgd 	aiov.iov_len = SCARG(uap, nbyte);
204d5ddeb04Sroot 	auio.uio_iov = &aiov;
205d5ddeb04Sroot 	auio.uio_iovcnt = 1;
206*00487f8cScgd 	auio.uio_resid = SCARG(uap, nbyte);
20795d9d7e5Smckusick 	auio.uio_rw = UIO_WRITE;
20895d9d7e5Smckusick 	auio.uio_segflg = UIO_USERSPACE;
20937dd6451Smckusick 	auio.uio_procp = p;
21095d9d7e5Smckusick #ifdef KTRACE
21195d9d7e5Smckusick 	/*
21295d9d7e5Smckusick 	 * if tracing, save a copy of iovec
21395d9d7e5Smckusick 	 */
21487836a50Smckusick 	if (KTRPOINT(p, KTR_GENIO))
21595d9d7e5Smckusick 		ktriov = aiov;
21695d9d7e5Smckusick #endif
217*00487f8cScgd 	cnt = SCARG(uap, nbyte);
218458b3cedSkarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
219458b3cedSkarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
220458b3cedSkarels 		    error == EINTR || error == EWOULDBLOCK))
221458b3cedSkarels 			error = 0;
222458b3cedSkarels 		if (error == EPIPE)
22387836a50Smckusick 			psignal(p, SIGPIPE);
22495d9d7e5Smckusick 	}
22595d9d7e5Smckusick 	cnt -= auio.uio_resid;
22695d9d7e5Smckusick #ifdef KTRACE
22787836a50Smckusick 	if (KTRPOINT(p, KTR_GENIO) && error == 0)
228*00487f8cScgd 		ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
229ee209021Smckusick 		    &ktriov, cnt, error);
23095d9d7e5Smckusick #endif
23187836a50Smckusick 	*retval = cnt;
2322c51c3e4Skarels 	return (error);
233828d9165Sroot }
234828d9165Sroot 
23587836a50Smckusick /*
23687836a50Smckusick  * Gather write system call
23787836a50Smckusick  */
238*00487f8cScgd int
writev(p,uap,retval)23941982c2cStorek writev(p, uap, retval)
24041982c2cStorek 	struct proc *p;
241*00487f8cScgd 	register struct writev_args /* {
242*00487f8cScgd 		syscallarg(int) fd;
243*00487f8cScgd 		syscallarg(struct iovec *) iovp;
244*00487f8cScgd 		syscallarg(u_int) iovcnt;
245*00487f8cScgd 	} */ *uap;
246*00487f8cScgd 	register_t *retval;
24787836a50Smckusick {
248d5ddeb04Sroot 	register struct file *fp;
249bcf289b6Smckusick 	register struct filedesc *fdp = p->p_fd;
25095d9d7e5Smckusick 	struct uio auio;
251d5ddeb04Sroot 	register struct iovec *iov;
2526b756a40Storek 	struct iovec *needfree;
25395d9d7e5Smckusick 	struct iovec aiov[UIO_SMALLIOV];
25495d9d7e5Smckusick 	long i, cnt, error = 0;
25540bd33f9Sbostic 	u_int iovlen;
256a2967617Skarels #ifdef KTRACE
257a2967617Skarels 	struct iovec *ktriov = NULL;
258a2967617Skarels #endif
259a2967617Skarels 
260*00487f8cScgd 	if (((u_int)SCARG(uap, fd)) >= fdp->fd_nfiles ||
261*00487f8cScgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
26295d9d7e5Smckusick 	    (fp->f_flag & FWRITE) == 0)
2632c51c3e4Skarels 		return (EBADF);
26439481ef4Skarels 	/* note: can't use iovlen until iovcnt is validated */
265*00487f8cScgd 	iovlen = SCARG(uap, iovcnt) * sizeof (struct iovec);
266*00487f8cScgd 	if (SCARG(uap, iovcnt) > UIO_SMALLIOV) {
267*00487f8cScgd 		if (SCARG(uap, iovcnt) > UIO_MAXIOV)
2682c51c3e4Skarels 			return (EINVAL);
26939481ef4Skarels 		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
2706b756a40Storek 		needfree = iov;
2716b756a40Storek 	} else {
27295d9d7e5Smckusick 		iov = aiov;
2736b756a40Storek 		needfree = NULL;
2746b756a40Storek 	}
27595d9d7e5Smckusick 	auio.uio_iov = iov;
276*00487f8cScgd 	auio.uio_iovcnt = SCARG(uap, iovcnt);
27795d9d7e5Smckusick 	auio.uio_rw = UIO_WRITE;
27895d9d7e5Smckusick 	auio.uio_segflg = UIO_USERSPACE;
27937dd6451Smckusick 	auio.uio_procp = p;
280*00487f8cScgd 	if (error = copyin((caddr_t)SCARG(uap, iovp), (caddr_t)iov, iovlen))
28195d9d7e5Smckusick 		goto done;
28295d9d7e5Smckusick 	auio.uio_resid = 0;
283*00487f8cScgd 	for (i = 0; i < SCARG(uap, iovcnt); i++) {
284b3c14c05Smckusick 		if (auio.uio_resid + iov->iov_len < auio.uio_resid) {
28595d9d7e5Smckusick 			error = EINVAL;
28695d9d7e5Smckusick 			goto done;
287d5ddeb04Sroot 		}
28895d9d7e5Smckusick 		auio.uio_resid += iov->iov_len;
28969d1c9ebSsam 		iov++;
290d5ddeb04Sroot 	}
291a2967617Skarels #ifdef KTRACE
29295d9d7e5Smckusick 	/*
29395d9d7e5Smckusick 	 * if tracing, save a copy of iovec
29495d9d7e5Smckusick 	 */
29587836a50Smckusick 	if (KTRPOINT(p, KTR_GENIO))  {
296a2967617Skarels 		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
29795d9d7e5Smckusick 		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
298a2967617Skarels 	}
299a2967617Skarels #endif
30095d9d7e5Smckusick 	cnt = auio.uio_resid;
301458b3cedSkarels 	if (error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred)) {
302458b3cedSkarels 		if (auio.uio_resid != cnt && (error == ERESTART ||
303458b3cedSkarels 		    error == EINTR || error == EWOULDBLOCK))
304458b3cedSkarels 			error = 0;
305458b3cedSkarels 		if (error == EPIPE)
30687836a50Smckusick 			psignal(p, SIGPIPE);
307b0c95adcSmckusick 	}
30895d9d7e5Smckusick 	cnt -= auio.uio_resid;
309a2967617Skarels #ifdef KTRACE
310a2967617Skarels 	if (ktriov != NULL) {
311817fcec3Smarc 		if (error == 0)
312*00487f8cScgd 			ktrgenio(p->p_tracep, SCARG(uap, fd), UIO_WRITE,
313ee209021Smckusick 				ktriov, cnt, error);
314a2967617Skarels 		FREE(ktriov, M_TEMP);
315a2967617Skarels 	}
316a2967617Skarels #endif
31787836a50Smckusick 	*retval = cnt;
31895d9d7e5Smckusick done:
3196b756a40Storek 	if (needfree)
3206b756a40Storek 		FREE(needfree, M_IOV);
3212c51c3e4Skarels 	return (error);
322d5ddeb04Sroot }
323d5ddeb04Sroot 
324c767fa90Sroot /*
325c767fa90Sroot  * Ioctl system call
326c767fa90Sroot  */
32741982c2cStorek /* ARGSUSED */
328*00487f8cScgd int
ioctl(p,uap,retval)32941982c2cStorek ioctl(p, uap, retval)
33041982c2cStorek 	struct proc *p;
331*00487f8cScgd 	register struct ioctl_args /* {
332*00487f8cScgd 		syscallarg(int) fd;
333*00487f8cScgd 		syscallarg(u_long) com;
334*00487f8cScgd 		syscallarg(caddr_t) data;
335*00487f8cScgd 	} */ *uap;
336*00487f8cScgd 	register_t *retval;
33787836a50Smckusick {
33887836a50Smckusick 	register struct file *fp;
3397585af12Sbostic 	register struct filedesc *fdp;
340*00487f8cScgd 	register u_long com;
341*00487f8cScgd 	register int error;
342d5ddeb04Sroot 	register u_int size;
3437585af12Sbostic 	caddr_t data, memp;
3447585af12Sbostic 	int tmp;
345b8805943Skarels #define STK_PARAMS	128
3460edb0603Skarels 	char stkbuf[STK_PARAMS];
347c767fa90Sroot 
3487585af12Sbostic 	fdp = p->p_fd;
349*00487f8cScgd 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
350*00487f8cScgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
3512c51c3e4Skarels 		return (EBADF);
3527585af12Sbostic 
353458b3cedSkarels 	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
3542c51c3e4Skarels 		return (EBADF);
355506962a6Ssam 
356*00487f8cScgd 	switch (com = SCARG(uap, com)) {
3577585af12Sbostic 	case FIONCLEX:
358*00487f8cScgd 		fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE;
3592c51c3e4Skarels 		return (0);
3607585af12Sbostic 	case FIOCLEX:
361*00487f8cScgd 		fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
3627585af12Sbostic 		return (0);
363c767fa90Sroot 	}
364506962a6Ssam 
365506962a6Ssam 	/*
3667585af12Sbostic 	 * Interpret high order word to find amount of data to be
3677585af12Sbostic 	 * copied to/from the user's address space.
368506962a6Ssam 	 */
369b8805943Skarels 	size = IOCPARM_LEN(com);
370458b3cedSkarels 	if (size > IOCPARM_MAX)
3712c51c3e4Skarels 		return (ENOTTY);
3727585af12Sbostic 	memp = NULL;
3730edb0603Skarels 	if (size > sizeof (stkbuf)) {
374bd7e0dabSmckusick 		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
375faf0051dSmckusick 		data = memp;
3767585af12Sbostic 	} else
3777585af12Sbostic 		data = stkbuf;
3785be745e3Ssam 	if (com&IOC_IN) {
3795be745e3Ssam 		if (size) {
380*00487f8cScgd 			error = copyin(SCARG(uap, data), data, (u_int)size);
381458b3cedSkarels 			if (error) {
382faf0051dSmckusick 				if (memp)
383faf0051dSmckusick 					free(memp, M_IOCTLOPS);
3842c51c3e4Skarels 				return (error);
385faf0051dSmckusick 			}
386506962a6Ssam 		} else
387*00487f8cScgd 			*(caddr_t *)data = SCARG(uap, data);
3885be745e3Ssam 	} else if ((com&IOC_OUT) && size)
389506962a6Ssam 		/*
390a2967617Skarels 		 * Zero the buffer so the user always
391a2967617Skarels 		 * gets back something deterministic.
392506962a6Ssam 		 */
393b8805943Skarels 		bzero(data, size);
3942a73ef0fSsam 	else if (com&IOC_VOID)
395*00487f8cScgd 		*(caddr_t *)data = SCARG(uap, data);
396506962a6Ssam 
397f655bc81Ssam 	switch (com) {
398506962a6Ssam 
399f655bc81Ssam 	case FIONBIO:
40037dd6451Smckusick 		if (tmp = *(int *)data)
40117cfc8d6Smckusick 			fp->f_flag |= FNONBLOCK;
40237dd6451Smckusick 		else
40317cfc8d6Smckusick 			fp->f_flag &= ~FNONBLOCK;
40437dd6451Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
405b8805943Skarels 		break;
406f655bc81Ssam 
407f655bc81Ssam 	case FIOASYNC:
40837dd6451Smckusick 		if (tmp = *(int *)data)
40937dd6451Smckusick 			fp->f_flag |= FASYNC;
41037dd6451Smckusick 		else
41137dd6451Smckusick 			fp->f_flag &= ~FASYNC;
41237dd6451Smckusick 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
413b8805943Skarels 		break;
414f655bc81Ssam 
415f655bc81Ssam 	case FIOSETOWN:
41637dd6451Smckusick 		tmp = *(int *)data;
41737dd6451Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
41837dd6451Smckusick 			((struct socket *)fp->f_data)->so_pgid = tmp;
41937dd6451Smckusick 			error = 0;
42037dd6451Smckusick 			break;
42137dd6451Smckusick 		}
42237dd6451Smckusick 		if (tmp <= 0) {
42337dd6451Smckusick 			tmp = -tmp;
42437dd6451Smckusick 		} else {
42537dd6451Smckusick 			struct proc *p1 = pfind(tmp);
42637dd6451Smckusick 			if (p1 == 0) {
42737dd6451Smckusick 				error = ESRCH;
42837dd6451Smckusick 				break;
42937dd6451Smckusick 			}
43037dd6451Smckusick 			tmp = p1->p_pgrp->pg_id;
43137dd6451Smckusick 		}
43237dd6451Smckusick 		error = (*fp->f_ops->fo_ioctl)
433*00487f8cScgd 			(fp, TIOCSPGRP, (caddr_t)&tmp, p);
434b8805943Skarels 		break;
435f655bc81Ssam 
436f655bc81Ssam 	case FIOGETOWN:
43737dd6451Smckusick 		if (fp->f_type == DTYPE_SOCKET) {
43837dd6451Smckusick 			error = 0;
43937dd6451Smckusick 			*(int *)data = ((struct socket *)fp->f_data)->so_pgid;
440b8805943Skarels 			break;
44137dd6451Smckusick 		}
442*00487f8cScgd 		error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data, p);
44337dd6451Smckusick 		*(int *)data = -*(int *)data;
44437dd6451Smckusick 		break;
44537dd6451Smckusick 
446b8805943Skarels 	default:
4470b0833e3Skarels 		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
448506962a6Ssam 		/*
449506962a6Ssam 		 * Copy any data to user, size was
450506962a6Ssam 		 * already set and checked above.
451506962a6Ssam 		 */
452458b3cedSkarels 		if (error == 0 && (com&IOC_OUT) && size)
453*00487f8cScgd 			error = copyout(data, SCARG(uap, data), (u_int)size);
454b8805943Skarels 		break;
455b8805943Skarels 	}
456faf0051dSmckusick 	if (memp)
457faf0051dSmckusick 		free(memp, M_IOCTLOPS);
4582c51c3e4Skarels 	return (error);
459c767fa90Sroot }
460c767fa90Sroot 
461c4490912Skarels int	selwait, nselcoll;
462be7d2a0dSkarels 
463be7d2a0dSkarels /*
464f655bc81Ssam  * Select system call.
465c767fa90Sroot  */
466*00487f8cScgd int
select(p,uap,retval)46741982c2cStorek select(p, uap, retval)
46841982c2cStorek 	register struct proc *p;
469*00487f8cScgd 	register struct select_args /* {
470*00487f8cScgd 		syscallarg(u_int) nd;
471*00487f8cScgd 		syscallarg(fd_set *) in;
472*00487f8cScgd 		syscallarg(fd_set *) ou;
473*00487f8cScgd 		syscallarg(fd_set *) ex;
474*00487f8cScgd 		syscallarg(struct timeval *) tv;
475*00487f8cScgd 	} */ *uap;
476*00487f8cScgd 	register_t *retval;
47787836a50Smckusick {
478ac0f205eSkarels 	fd_set ibits[3], obits[3];
479f655bc81Ssam 	struct timeval atv;
480a30ab6f6Smckusick 	int s, ncoll, error, timo = 0;
4817ac4a081Smckusick 	u_int ni;
482f655bc81Ssam 
483b87e53fbSkarels 	bzero((caddr_t)ibits, sizeof(ibits));
484b87e53fbSkarels 	bzero((caddr_t)obits, sizeof(obits));
485*00487f8cScgd 	if (SCARG(uap, nd) > FD_SETSIZE)
4867ac4a081Smckusick 		return (EINVAL);
487*00487f8cScgd 	if (SCARG(uap, nd) > p->p_fd->fd_nfiles) {
488*00487f8cScgd 		/* forgiving; slightly wrong */
489*00487f8cScgd 		SCARG(uap, nd) = p->p_fd->fd_nfiles;
490*00487f8cScgd 	}
491*00487f8cScgd 	ni = howmany(SCARG(uap, nd), NFDBITS) * sizeof(fd_mask);
492f655bc81Ssam 
493f655bc81Ssam #define	getbits(name, x) \
494*00487f8cScgd 	if (SCARG(uap, name) && (error = copyin((caddr_t)SCARG(uap, name), \
495*00487f8cScgd 	    (caddr_t)&ibits[x], ni))) \
4967ac4a081Smckusick 		goto done;
497f655bc81Ssam 	getbits(in, 0);
498f655bc81Ssam 	getbits(ou, 1);
499f655bc81Ssam 	getbits(ex, 2);
500f655bc81Ssam #undef	getbits
501f655bc81Ssam 
502*00487f8cScgd 	if (SCARG(uap, tv)) {
503*00487f8cScgd 		error = copyin((caddr_t)SCARG(uap, tv), (caddr_t)&atv,
504f655bc81Ssam 			sizeof (atv));
505458b3cedSkarels 		if (error)
506f655bc81Ssam 			goto done;
507f655bc81Ssam 		if (itimerfix(&atv)) {
508458b3cedSkarels 			error = EINVAL;
509f655bc81Ssam 			goto done;
510f655bc81Ssam 		}
51145922107Storek 		s = splclock();
51245922107Storek 		timevaladd(&atv, (struct timeval *)&time);
513692e3f19Sbostic 		splx(s);
514a30ab6f6Smckusick 	}
515f655bc81Ssam retry:
516f655bc81Ssam 	ncoll = nselcoll;
51799887da3Sbostic 	p->p_flag |= P_SELECT;
518*00487f8cScgd 	error = selscan(p, ibits, obits, SCARG(uap, nd), retval);
51987836a50Smckusick 	if (error || *retval)
520f655bc81Ssam 		goto done;
521e1ad4c2bSkarels 	s = splhigh();
522*00487f8cScgd 	if (SCARG(uap, tv)) {
523860e4a7aSmckusick 		if (timercmp(&time, &atv, >=)) {
524f655bc81Ssam 			splx(s);
525f655bc81Ssam 			goto done;
526f655bc81Ssam 		}
527860e4a7aSmckusick 		/*
528a30ab6f6Smckusick 		 * If poll wait was tiny, this could be zero; we will
529a30ab6f6Smckusick 		 * have to round it up to avoid sleeping forever.  If
530a30ab6f6Smckusick 		 * we retry below, the timercmp above will get us out.
531a30ab6f6Smckusick 		 * Note that if wait was 0, the timercmp will prevent
532a30ab6f6Smckusick 		 * us from getting here the first time.
533860e4a7aSmckusick 		 */
534a30ab6f6Smckusick 		timo = hzto(&atv);
535a30ab6f6Smckusick 		if (timo == 0)
536860e4a7aSmckusick 			timo = 1;
537860e4a7aSmckusick 	}
53899887da3Sbostic 	if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
539f655bc81Ssam 		splx(s);
540f655bc81Ssam 		goto retry;
541f655bc81Ssam 	}
54299887da3Sbostic 	p->p_flag &= ~P_SELECT;
543458b3cedSkarels 	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
544f655bc81Ssam 	splx(s);
545458b3cedSkarels 	if (error == 0)
546f655bc81Ssam 		goto retry;
547f655bc81Ssam done:
54899887da3Sbostic 	p->p_flag &= ~P_SELECT;
549458b3cedSkarels 	/* select is not restarted after signals... */
550458b3cedSkarels 	if (error == ERESTART)
551458b3cedSkarels 		error = EINTR;
552458b3cedSkarels 	if (error == EWOULDBLOCK)
553458b3cedSkarels 		error = 0;
554f655bc81Ssam #define	putbits(name, x) \
555*00487f8cScgd 	if (SCARG(uap, name) && (error2 = copyout((caddr_t)&obits[x], \
556*00487f8cScgd 	    (caddr_t)SCARG(uap, name), ni))) \
5577ac4a081Smckusick 		error = error2;
558458b3cedSkarels 	if (error == 0) {
5597ac4a081Smckusick 		int error2;
5607ac4a081Smckusick 
561f655bc81Ssam 		putbits(in, 0);
562f655bc81Ssam 		putbits(ou, 1);
563f655bc81Ssam 		putbits(ex, 2);
564f655bc81Ssam #undef putbits
565f655bc81Ssam 	}
5662c51c3e4Skarels 	return (error);
567cee5ee1eSkarels }
568f655bc81Ssam 
569*00487f8cScgd int
selscan(p,ibits,obits,nfd,retval)5700b0833e3Skarels selscan(p, ibits, obits, nfd, retval)
5710b0833e3Skarels 	struct proc *p;
572ac0f205eSkarels 	fd_set *ibits, *obits;
573*00487f8cScgd 	int nfd;
574*00487f8cScgd 	register_t *retval;
575f655bc81Ssam {
5760b0833e3Skarels 	register struct filedesc *fdp = p->p_fd;
5776b756a40Storek 	register int msk, i, j, fd;
578ac0f205eSkarels 	register fd_mask bits;
579f655bc81Ssam 	struct file *fp;
5806b756a40Storek 	int n = 0;
5816b756a40Storek 	static int flag[3] = { FREAD, FWRITE, 0 };
582f655bc81Ssam 
5836b756a40Storek 	for (msk = 0; msk < 3; msk++) {
584ac0f205eSkarels 		for (i = 0; i < nfd; i += NFDBITS) {
5856b756a40Storek 			bits = ibits[msk].fds_bits[i/NFDBITS];
5866b756a40Storek 			while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
587be7d2a0dSkarels 				bits &= ~(1 << j);
5886b756a40Storek 				fp = fdp->fd_ofiles[fd];
5896b756a40Storek 				if (fp == NULL)
5906b756a40Storek 					return (EBADF);
5916b756a40Storek 				if ((*fp->f_ops->fo_select)(fp, flag[msk], p)) {
5926b756a40Storek 					FD_SET(fd, &obits[msk]);
593f655bc81Ssam 					n++;
594f655bc81Ssam 				}
595f655bc81Ssam 			}
596f655bc81Ssam 		}
597be7d2a0dSkarels 	}
59887836a50Smckusick 	*retval = n;
5996b756a40Storek 	return (0);
600f655bc81Ssam }
601f655bc81Ssam 
602c767fa90Sroot /*ARGSUSED*/
603*00487f8cScgd int
seltrue(dev,flag,p)6040b0833e3Skarels seltrue(dev, flag, p)
605f655bc81Ssam 	dev_t dev;
606f655bc81Ssam 	int flag;
6070b0833e3Skarels 	struct proc *p;
608c767fa90Sroot {
609c767fa90Sroot 
610f655bc81Ssam 	return (1);
611c767fa90Sroot }
61272762883Sroot 
6138731788dSmckusick /*
6148731788dSmckusick  * Record a select request.
6158731788dSmckusick  */
6168731788dSmckusick void
selrecord(selector,sip)6178731788dSmckusick selrecord(selector, sip)
6188731788dSmckusick 	struct proc *selector;
6198731788dSmckusick 	struct selinfo *sip;
62072762883Sroot {
6218731788dSmckusick 	struct proc *p;
6228731788dSmckusick 	pid_t mypid;
62372762883Sroot 
6248731788dSmckusick 	mypid = selector->p_pid;
6258731788dSmckusick 	if (sip->si_pid == mypid)
6268731788dSmckusick 		return;
6278731788dSmckusick 	if (sip->si_pid && (p = pfind(sip->si_pid)) &&
6288731788dSmckusick 	    p->p_wchan == (caddr_t)&selwait)
6298731788dSmckusick 		sip->si_flags |= SI_COLL;
6308731788dSmckusick 	else
6318731788dSmckusick 		sip->si_pid = mypid;
6328731788dSmckusick }
6338731788dSmckusick 
6348731788dSmckusick /*
6358731788dSmckusick  * Do a wakeup when a selectable event occurs.
6368731788dSmckusick  */
6378731788dSmckusick void
selwakeup(sip)6388731788dSmckusick selwakeup(sip)
6398731788dSmckusick 	register struct selinfo *sip;
6408731788dSmckusick {
6418731788dSmckusick 	register struct proc *p;
6428731788dSmckusick 	int s;
6438731788dSmckusick 
6448731788dSmckusick 	if (sip->si_pid == 0)
6458731788dSmckusick 		return;
6468731788dSmckusick 	if (sip->si_flags & SI_COLL) {
647f655bc81Ssam 		nselcoll++;
6488731788dSmckusick 		sip->si_flags &= ~SI_COLL;
649f655bc81Ssam 		wakeup((caddr_t)&selwait);
650f655bc81Ssam 	}
651774d6900Smckusick 	p = pfind(sip->si_pid);
6528731788dSmckusick 	sip->si_pid = 0;
653774d6900Smckusick 	if (p != NULL) {
6548731788dSmckusick 		s = splhigh();
655bc41b6b9Skarels 		if (p->p_wchan == (caddr_t)&selwait) {
656bc41b6b9Skarels 			if (p->p_stat == SSLEEP)
6577585af12Sbostic 				setrunnable(p);
658bc41b6b9Skarels 			else
659bc41b6b9Skarels 				unsleep(p);
66099887da3Sbostic 		} else if (p->p_flag & P_SELECT)
66199887da3Sbostic 			p->p_flag &= ~P_SELECT;
662f655bc81Ssam 		splx(s);
663f655bc81Ssam 	}
66472762883Sroot }
665