sys_generic.c revision 50477
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1982, 1986, 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes * (c) UNIX System Laboratories, Inc.
51541Srgrimes * All or some portions of this file are derived from material licensed
61541Srgrimes * to the University of California by American Telephone and Telegraph
71541Srgrimes * Co. or Unix System Laboratories, Inc. and are reproduced herein with
81541Srgrimes * the permission of UNIX System Laboratories, Inc.
91541Srgrimes *
101541Srgrimes * Redistribution and use in source and binary forms, with or without
111541Srgrimes * modification, are permitted provided that the following conditions
121541Srgrimes * are met:
131541Srgrimes * 1. Redistributions of source code must retain the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer.
151541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161541Srgrimes *    notice, this list of conditions and the following disclaimer in the
171541Srgrimes *    documentation and/or other materials provided with the distribution.
181541Srgrimes * 3. All advertising materials mentioning features or use of this software
191541Srgrimes *    must display the following acknowledgement:
201541Srgrimes *	This product includes software developed by the University of
211541Srgrimes *	California, Berkeley and its contributors.
221541Srgrimes * 4. Neither the name of the University nor the names of its contributors
231541Srgrimes *    may be used to endorse or promote products derived from this software
241541Srgrimes *    without specific prior written permission.
251541Srgrimes *
261541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361541Srgrimes * SUCH DAMAGE.
371541Srgrimes *
381541Srgrimes *	@(#)sys_generic.c	8.5 (Berkeley) 1/21/94
3950477Speter * $FreeBSD: head/sys/kern/sys_generic.c 50477 1999-08-28 01:08:13Z peter $
401541Srgrimes */
411541Srgrimes
4213203Swollman#include "opt_ktrace.h"
4313203Swollman
441541Srgrimes#include <sys/param.h>
451541Srgrimes#include <sys/systm.h>
4612221Sbde#include <sys/sysproto.h>
471541Srgrimes#include <sys/filedesc.h>
4824206Sbde#include <sys/filio.h>
4924206Sbde#include <sys/ttycom.h>
5024131Sbde#include <sys/fcntl.h>
511541Srgrimes#include <sys/file.h>
521541Srgrimes#include <sys/proc.h>
533308Sphk#include <sys/signalvar.h>
541541Srgrimes#include <sys/socketvar.h>
551541Srgrimes#include <sys/uio.h>
561541Srgrimes#include <sys/kernel.h>
571541Srgrimes#include <sys/malloc.h>
5829351Speter#include <sys/poll.h>
5929351Speter#include <sys/sysent.h>
601541Srgrimes#ifdef KTRACE
611541Srgrimes#include <sys/ktrace.h>
621541Srgrimes#endif
631541Srgrimes
6438517Sdfr#include <machine/limits.h>
6538517Sdfr
6630354Sphkstatic MALLOC_DEFINE(M_IOCTLOPS, "ioctlops", "ioctl data buffer");
6730354Sphkstatic MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
6830354SphkMALLOC_DEFINE(M_IOV, "iov", "large iov's");
6930309Sphk
7031364Sbdestatic int	pollscan __P((struct proc *, struct pollfd *, int));
7130994Sphkstatic int	selscan __P((struct proc *, fd_mask **, fd_mask **, int));
7245311Sdtstatic struct file* getfp __P((struct filedesc *, int, int));
7345311Sdtstatic int	dofileread __P((struct proc *, struct file *, int, void *,
7445311Sdt		    size_t, off_t, int));
7545311Sdtstatic int	dofilewrite __P((struct proc *, struct file *, int,
7645311Sdt		    const void *, size_t, off_t, int));
773485Sphk
7845311Sdtstatic struct file*
7945311Sdtgetfp(fdp, fd, flag)
8045311Sdt	struct filedesc* fdp;
8145311Sdt	int fd, flag;
8245311Sdt{
8345311Sdt	struct file* fp;
8445311Sdt
8545311Sdt	if (((u_int)fd) >= fdp->fd_nfiles ||
8645311Sdt	    (fp = fdp->fd_ofiles[fd]) == NULL ||
8745311Sdt	    (fp->f_flag & flag) == 0)
8845311Sdt		return (NULL);
8945311Sdt	return (fp);
9045311Sdt}
9145311Sdt
921541Srgrimes/*
931541Srgrimes * Read system call.
941541Srgrimes */
9512221Sbde#ifndef _SYS_SYSPROTO_H_
961541Srgrimesstruct read_args {
971541Srgrimes	int	fd;
9838864Sbde	void	*buf;
9938864Sbde	size_t	nbyte;
1001541Srgrimes};
10112221Sbde#endif
1021549Srgrimesint
10330994Sphkread(p, uap)
1041541Srgrimes	struct proc *p;
1051541Srgrimes	register struct read_args *uap;
1061541Srgrimes{
1071541Srgrimes	register struct file *fp;
1081541Srgrimes
10945311Sdt	if ((fp = getfp(p->p_fd, uap->fd, FREAD)) == NULL)
1101541Srgrimes		return (EBADF);
11145311Sdt	return (dofileread(p, fp, uap->fd, uap->buf, uap->nbyte, (off_t)-1, 0));
1121541Srgrimes}
1131541Srgrimes
1141541Srgrimes/*
11545311Sdt * Pread system call
11645065Salc */
11745065Salc#ifndef _SYS_SYSPROTO_H_
11845065Salcstruct pread_args {
11945065Salc	int	fd;
12045065Salc	void	*buf;
12145065Salc	size_t	nbyte;
12245311Sdt	int	pad;
12345311Sdt	off_t	offset;
12445065Salc};
12545065Salc#endif
12645065Salcint
12745065Salcpread(p, uap)
12845065Salc	struct proc *p;
12945065Salc	register struct pread_args *uap;
13045065Salc{
13145065Salc	register struct file *fp;
13245311Sdt
13345311Sdt	if ((fp = getfp(p->p_fd, uap->fd, FREAD)) == NULL)
13445311Sdt		return (EBADF);
13545311Sdt	if (fp->f_type != DTYPE_VNODE)
13645311Sdt		return (ESPIPE);
13745311Sdt	return (dofileread(p, fp, uap->fd, uap->buf, uap->nbyte, uap->offset,
13845311Sdt	    FOF_OFFSET));
13945311Sdt}
14045311Sdt
14145311Sdt/*
14245311Sdt * Code common for read and pread
14345311Sdt */
14445311Sdtint
14545311Sdtdofileread(p, fp, fd, buf, nbyte, offset, flags)
14645311Sdt	struct proc *p;
14745311Sdt	struct file *fp;
14845311Sdt	int fd, flags;
14945311Sdt	void *buf;
15045311Sdt	size_t nbyte;
15145311Sdt	off_t offset;
15245311Sdt{
15345065Salc	struct uio auio;
15445065Salc	struct iovec aiov;
15545065Salc	long cnt, error = 0;
15645065Salc#ifdef KTRACE
15745065Salc	struct iovec ktriov;
15845065Salc#endif
15945065Salc
16045311Sdt	aiov.iov_base = (caddr_t)buf;
16145311Sdt	aiov.iov_len = nbyte;
16245065Salc	auio.uio_iov = &aiov;
16345065Salc	auio.uio_iovcnt = 1;
16445311Sdt	auio.uio_offset = offset;
16545311Sdt	if (nbyte > INT_MAX)
16645065Salc		return (EINVAL);
16745311Sdt	auio.uio_resid = nbyte;
16845065Salc	auio.uio_rw = UIO_READ;
16945065Salc	auio.uio_segflg = UIO_USERSPACE;
17045065Salc	auio.uio_procp = p;
17145065Salc#ifdef KTRACE
17245065Salc	/*
17345065Salc	 * if tracing, save a copy of iovec
17445065Salc	 */
17545065Salc	if (KTRPOINT(p, KTR_GENIO))
17645065Salc		ktriov = aiov;
17745065Salc#endif
17845311Sdt	cnt = nbyte;
17945311Sdt	if ((error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred, flags)))
18045065Salc		if (auio.uio_resid != cnt && (error == ERESTART ||
18145065Salc		    error == EINTR || error == EWOULDBLOCK))
18245065Salc			error = 0;
18345065Salc	cnt -= auio.uio_resid;
18445065Salc#ifdef KTRACE
18545065Salc	if (KTRPOINT(p, KTR_GENIO) && error == 0)
18645311Sdt		ktrgenio(p->p_tracep, fd, UIO_READ, &ktriov, cnt, error);
18745065Salc#endif
18845065Salc	p->p_retval[0] = cnt;
18945065Salc	return (error);
19045065Salc}
19145065Salc
19245065Salc/*
1931541Srgrimes * Scatter read system call.
1941541Srgrimes */
19512221Sbde#ifndef _SYS_SYSPROTO_H_
1961541Srgrimesstruct readv_args {
19712208Sbde	int	fd;
1981541Srgrimes	struct	iovec *iovp;
1991541Srgrimes	u_int	iovcnt;
2001541Srgrimes};
20112221Sbde#endif
2021549Srgrimesint
20330994Sphkreadv(p, uap)
2041541Srgrimes	struct proc *p;
2051541Srgrimes	register struct readv_args *uap;
2061541Srgrimes{
2071541Srgrimes	register struct file *fp;
2081541Srgrimes	register struct filedesc *fdp = p->p_fd;
2091541Srgrimes	struct uio auio;
2101541Srgrimes	register struct iovec *iov;
2111541Srgrimes	struct iovec *needfree;
2121541Srgrimes	struct iovec aiov[UIO_SMALLIOV];
2131541Srgrimes	long i, cnt, error = 0;
2141541Srgrimes	u_int iovlen;
2151541Srgrimes#ifdef KTRACE
2161541Srgrimes	struct iovec *ktriov = NULL;
2171541Srgrimes#endif
2181541Srgrimes
21945311Sdt	if ((fp = getfp(fdp, uap->fd, FREAD)) == NULL)
2201541Srgrimes		return (EBADF);
2211541Srgrimes	/* note: can't use iovlen until iovcnt is validated */
2221541Srgrimes	iovlen = uap->iovcnt * sizeof (struct iovec);
2231541Srgrimes	if (uap->iovcnt > UIO_SMALLIOV) {
2241541Srgrimes		if (uap->iovcnt > UIO_MAXIOV)
2251541Srgrimes			return (EINVAL);
2261541Srgrimes		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
2271541Srgrimes		needfree = iov;
2281541Srgrimes	} else {
2291541Srgrimes		iov = aiov;
2301541Srgrimes		needfree = NULL;
2311541Srgrimes	}
2321541Srgrimes	auio.uio_iov = iov;
2331541Srgrimes	auio.uio_iovcnt = uap->iovcnt;
2341541Srgrimes	auio.uio_rw = UIO_READ;
2351541Srgrimes	auio.uio_segflg = UIO_USERSPACE;
2361541Srgrimes	auio.uio_procp = p;
23726671Sdyson	auio.uio_offset = -1;
2383098Sphk	if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
2391541Srgrimes		goto done;
2401541Srgrimes	auio.uio_resid = 0;
2411541Srgrimes	for (i = 0; i < uap->iovcnt; i++) {
24238517Sdfr		if (iov->iov_len > INT_MAX - auio.uio_resid) {
2431541Srgrimes			error = EINVAL;
2441541Srgrimes			goto done;
2451541Srgrimes		}
24638517Sdfr		auio.uio_resid += iov->iov_len;
2471541Srgrimes		iov++;
2481541Srgrimes	}
2491541Srgrimes#ifdef KTRACE
2501541Srgrimes	/*
2511541Srgrimes	 * if tracing, save a copy of iovec
2521541Srgrimes	 */
2531541Srgrimes	if (KTRPOINT(p, KTR_GENIO))  {
2541541Srgrimes		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
2551541Srgrimes		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
2561541Srgrimes	}
2571541Srgrimes#endif
2581541Srgrimes	cnt = auio.uio_resid;
25945311Sdt	if ((error = (*fp->f_ops->fo_read)(fp, &auio, fp->f_cred, 0)))
2601541Srgrimes		if (auio.uio_resid != cnt && (error == ERESTART ||
2611541Srgrimes		    error == EINTR || error == EWOULDBLOCK))
2621541Srgrimes			error = 0;
2631541Srgrimes	cnt -= auio.uio_resid;
2641541Srgrimes#ifdef KTRACE
2651541Srgrimes	if (ktriov != NULL) {
2661541Srgrimes		if (error == 0)
26712208Sbde			ktrgenio(p->p_tracep, uap->fd, UIO_READ, ktriov,
2681541Srgrimes			    cnt, error);
2691541Srgrimes		FREE(ktriov, M_TEMP);
2701541Srgrimes	}
2711541Srgrimes#endif
27230994Sphk	p->p_retval[0] = cnt;
2731541Srgrimesdone:
2741541Srgrimes	if (needfree)
2751541Srgrimes		FREE(needfree, M_IOV);
2761541Srgrimes	return (error);
2771541Srgrimes}
2781541Srgrimes
2791541Srgrimes/*
2801541Srgrimes * Write system call
2811541Srgrimes */
28212221Sbde#ifndef _SYS_SYSPROTO_H_
2831541Srgrimesstruct write_args {
2841541Srgrimes	int	fd;
28538864Sbde	const void *buf;
28638864Sbde	size_t	nbyte;
2871541Srgrimes};
28812221Sbde#endif
2891549Srgrimesint
29030994Sphkwrite(p, uap)
2911541Srgrimes	struct proc *p;
2921541Srgrimes	register struct write_args *uap;
2931541Srgrimes{
2941541Srgrimes	register struct file *fp;
2951541Srgrimes
29645311Sdt	if ((fp = getfp(p->p_fd, uap->fd, FWRITE)) == NULL)
2971541Srgrimes		return (EBADF);
29845311Sdt	return (dofilewrite(p, fp, uap->fd, uap->buf, uap->nbyte, (off_t)-1, 0));
2991541Srgrimes}
3001541Srgrimes
3011541Srgrimes/*
30245311Sdt * Pwrite system call
30345065Salc */
30445065Salc#ifndef _SYS_SYSPROTO_H_
30545065Salcstruct pwrite_args {
30645065Salc	int	fd;
30745065Salc	const void *buf;
30845065Salc	size_t	nbyte;
30945311Sdt	int	pad;
31045311Sdt	off_t	offset;
31145065Salc};
31245065Salc#endif
31345065Salcint
31445065Salcpwrite(p, uap)
31545065Salc	struct proc *p;
31645065Salc	register struct pwrite_args *uap;
31745065Salc{
31845065Salc	register struct file *fp;
31945311Sdt
32045311Sdt	if ((fp = getfp(p->p_fd, uap->fd, FWRITE)) == NULL)
32145311Sdt		return (EBADF);
32245311Sdt	if (fp->f_type != DTYPE_VNODE)
32345311Sdt		return (ESPIPE);
32445311Sdt	return (dofilewrite(p, fp, uap->fd, uap->buf, uap->nbyte, uap->offset,
32545311Sdt	    FOF_OFFSET));
32645311Sdt}
32745311Sdt
32845311Sdtstatic int
32945311Sdtdofilewrite(p, fp, fd, buf, nbyte, offset, flags)
33045311Sdt	struct proc *p;
33145311Sdt	struct file *fp;
33245311Sdt	int fd, flags;
33345311Sdt	const void *buf;
33445311Sdt	size_t nbyte;
33545311Sdt	off_t offset;
33645311Sdt{
33745065Salc	struct uio auio;
33845065Salc	struct iovec aiov;
33945065Salc	long cnt, error = 0;
34045065Salc#ifdef KTRACE
34145065Salc	struct iovec ktriov;
34245065Salc#endif
34345065Salc
34445311Sdt	aiov.iov_base = (void *)buf;
34545311Sdt	aiov.iov_len = nbyte;
34645065Salc	auio.uio_iov = &aiov;
34745065Salc	auio.uio_iovcnt = 1;
34845311Sdt	auio.uio_offset = offset;
34945311Sdt	if (nbyte > INT_MAX)
35045065Salc		return (EINVAL);
35145311Sdt	auio.uio_resid = nbyte;
35245065Salc	auio.uio_rw = UIO_WRITE;
35345065Salc	auio.uio_segflg = UIO_USERSPACE;
35445065Salc	auio.uio_procp = p;
35545065Salc#ifdef KTRACE
35645065Salc	/*
35745065Salc	 * if tracing, save a copy of iovec
35845065Salc	 */
35945065Salc	if (KTRPOINT(p, KTR_GENIO))
36045065Salc		ktriov = aiov;
36145065Salc#endif
36245311Sdt	cnt = nbyte;
36345311Sdt	if ((error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred, flags))) {
36445065Salc		if (auio.uio_resid != cnt && (error == ERESTART ||
36545065Salc		    error == EINTR || error == EWOULDBLOCK))
36645065Salc			error = 0;
36745065Salc		if (error == EPIPE)
36845065Salc			psignal(p, SIGPIPE);
36945065Salc	}
37045065Salc	cnt -= auio.uio_resid;
37145065Salc#ifdef KTRACE
37245065Salc	if (KTRPOINT(p, KTR_GENIO) && error == 0)
37345311Sdt		ktrgenio(p->p_tracep, fd, UIO_WRITE,
37445065Salc		    &ktriov, cnt, error);
37545065Salc#endif
37645065Salc	p->p_retval[0] = cnt;
37745065Salc	return (error);
37845065Salc}
37945065Salc
38045065Salc/*
3811541Srgrimes * Gather write system call
3821541Srgrimes */
38312221Sbde#ifndef _SYS_SYSPROTO_H_
3841541Srgrimesstruct writev_args {
3851541Srgrimes	int	fd;
3861541Srgrimes	struct	iovec *iovp;
3871541Srgrimes	u_int	iovcnt;
3881541Srgrimes};
38912221Sbde#endif
3901549Srgrimesint
39130994Sphkwritev(p, uap)
3921541Srgrimes	struct proc *p;
3931541Srgrimes	register struct writev_args *uap;
3941541Srgrimes{
3951541Srgrimes	register struct file *fp;
3961541Srgrimes	register struct filedesc *fdp = p->p_fd;
3971541Srgrimes	struct uio auio;
3981541Srgrimes	register struct iovec *iov;
3991541Srgrimes	struct iovec *needfree;
4001541Srgrimes	struct iovec aiov[UIO_SMALLIOV];
4011541Srgrimes	long i, cnt, error = 0;
4021541Srgrimes	u_int iovlen;
4031541Srgrimes#ifdef KTRACE
4041541Srgrimes	struct iovec *ktriov = NULL;
4051541Srgrimes#endif
4061541Srgrimes
40745311Sdt	if ((fp = getfp(fdp, uap->fd, FWRITE)) == NULL)
4081541Srgrimes		return (EBADF);
4091541Srgrimes	/* note: can't use iovlen until iovcnt is validated */
4101541Srgrimes	iovlen = uap->iovcnt * sizeof (struct iovec);
4111541Srgrimes	if (uap->iovcnt > UIO_SMALLIOV) {
4121541Srgrimes		if (uap->iovcnt > UIO_MAXIOV)
4131541Srgrimes			return (EINVAL);
4141541Srgrimes		MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK);
4151541Srgrimes		needfree = iov;
4161541Srgrimes	} else {
4171541Srgrimes		iov = aiov;
4181541Srgrimes		needfree = NULL;
4191541Srgrimes	}
4201541Srgrimes	auio.uio_iov = iov;
4211541Srgrimes	auio.uio_iovcnt = uap->iovcnt;
4221541Srgrimes	auio.uio_rw = UIO_WRITE;
4231541Srgrimes	auio.uio_segflg = UIO_USERSPACE;
4241541Srgrimes	auio.uio_procp = p;
42526671Sdyson	auio.uio_offset = -1;
4263098Sphk	if ((error = copyin((caddr_t)uap->iovp, (caddr_t)iov, iovlen)))
4271541Srgrimes		goto done;
4281541Srgrimes	auio.uio_resid = 0;
4291541Srgrimes	for (i = 0; i < uap->iovcnt; i++) {
43038517Sdfr		if (iov->iov_len > INT_MAX - auio.uio_resid) {
4311541Srgrimes			error = EINVAL;
4321541Srgrimes			goto done;
4331541Srgrimes		}
43438517Sdfr		auio.uio_resid += iov->iov_len;
4351541Srgrimes		iov++;
4361541Srgrimes	}
4371541Srgrimes#ifdef KTRACE
4381541Srgrimes	/*
4391541Srgrimes	 * if tracing, save a copy of iovec
4401541Srgrimes	 */
4411541Srgrimes	if (KTRPOINT(p, KTR_GENIO))  {
4421541Srgrimes		MALLOC(ktriov, struct iovec *, iovlen, M_TEMP, M_WAITOK);
4431541Srgrimes		bcopy((caddr_t)auio.uio_iov, (caddr_t)ktriov, iovlen);
4441541Srgrimes	}
4451541Srgrimes#endif
4461541Srgrimes	cnt = auio.uio_resid;
44745311Sdt	if ((error = (*fp->f_ops->fo_write)(fp, &auio, fp->f_cred, 0))) {
4481541Srgrimes		if (auio.uio_resid != cnt && (error == ERESTART ||
4491541Srgrimes		    error == EINTR || error == EWOULDBLOCK))
4501541Srgrimes			error = 0;
4511541Srgrimes		if (error == EPIPE)
4521541Srgrimes			psignal(p, SIGPIPE);
4531541Srgrimes	}
4541541Srgrimes	cnt -= auio.uio_resid;
4551541Srgrimes#ifdef KTRACE
4561541Srgrimes	if (ktriov != NULL) {
4571541Srgrimes		if (error == 0)
4581541Srgrimes			ktrgenio(p->p_tracep, uap->fd, UIO_WRITE,
4591541Srgrimes				ktriov, cnt, error);
4601541Srgrimes		FREE(ktriov, M_TEMP);
4611541Srgrimes	}
4621541Srgrimes#endif
46330994Sphk	p->p_retval[0] = cnt;
4641541Srgrimesdone:
4651541Srgrimes	if (needfree)
4661541Srgrimes		FREE(needfree, M_IOV);
4671541Srgrimes	return (error);
4681541Srgrimes}
4691541Srgrimes
4701541Srgrimes/*
4711541Srgrimes * Ioctl system call
4721541Srgrimes */
47312221Sbde#ifndef _SYS_SYSPROTO_H_
4741541Srgrimesstruct ioctl_args {
4751541Srgrimes	int	fd;
47638517Sdfr	u_long	com;
4771541Srgrimes	caddr_t	data;
4781541Srgrimes};
47912221Sbde#endif
4801541Srgrimes/* ARGSUSED */
4811549Srgrimesint
48230994Sphkioctl(p, uap)
4831541Srgrimes	struct proc *p;
4841541Srgrimes	register struct ioctl_args *uap;
4851541Srgrimes{
4861541Srgrimes	register struct file *fp;
4871541Srgrimes	register struct filedesc *fdp;
48836846Sdfr	register u_long com;
48936846Sdfr	int error;
4901541Srgrimes	register u_int size;
4911541Srgrimes	caddr_t data, memp;
4921541Srgrimes	int tmp;
4931541Srgrimes#define STK_PARAMS	128
4941541Srgrimes	char stkbuf[STK_PARAMS];
4951541Srgrimes
4961541Srgrimes	fdp = p->p_fd;
4971541Srgrimes	if ((u_int)uap->fd >= fdp->fd_nfiles ||
4981541Srgrimes	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
4991541Srgrimes		return (EBADF);
5001541Srgrimes
5011541Srgrimes	if ((fp->f_flag & (FREAD | FWRITE)) == 0)
5021541Srgrimes		return (EBADF);
5031541Srgrimes
5041541Srgrimes	switch (com = uap->com) {
5051541Srgrimes	case FIONCLEX:
5061541Srgrimes		fdp->fd_ofileflags[uap->fd] &= ~UF_EXCLOSE;
5071541Srgrimes		return (0);
5081541Srgrimes	case FIOCLEX:
5091541Srgrimes		fdp->fd_ofileflags[uap->fd] |= UF_EXCLOSE;
5101541Srgrimes		return (0);
5111541Srgrimes	}
5121541Srgrimes
5131541Srgrimes	/*
5141541Srgrimes	 * Interpret high order word to find amount of data to be
5151541Srgrimes	 * copied to/from the user's address space.
5161541Srgrimes	 */
5171541Srgrimes	size = IOCPARM_LEN(com);
5181541Srgrimes	if (size > IOCPARM_MAX)
5191541Srgrimes		return (ENOTTY);
5201541Srgrimes	memp = NULL;
5211541Srgrimes	if (size > sizeof (stkbuf)) {
5221541Srgrimes		memp = (caddr_t)malloc((u_long)size, M_IOCTLOPS, M_WAITOK);
5231541Srgrimes		data = memp;
5241541Srgrimes	} else
5251541Srgrimes		data = stkbuf;
5261541Srgrimes	if (com&IOC_IN) {
5271541Srgrimes		if (size) {
5281541Srgrimes			error = copyin(uap->data, data, (u_int)size);
5291541Srgrimes			if (error) {
5301541Srgrimes				if (memp)
5311541Srgrimes					free(memp, M_IOCTLOPS);
5321541Srgrimes				return (error);
5331541Srgrimes			}
5341541Srgrimes		} else
5351541Srgrimes			*(caddr_t *)data = uap->data;
5361541Srgrimes	} else if ((com&IOC_OUT) && size)
5371541Srgrimes		/*
5381541Srgrimes		 * Zero the buffer so the user always
5391541Srgrimes		 * gets back something deterministic.
5401541Srgrimes		 */
5411541Srgrimes		bzero(data, size);
5421541Srgrimes	else if (com&IOC_VOID)
5431541Srgrimes		*(caddr_t *)data = uap->data;
5441541Srgrimes
5451541Srgrimes	switch (com) {
5461541Srgrimes
5471541Srgrimes	case FIONBIO:
5483098Sphk		if ((tmp = *(int *)data))
5491541Srgrimes			fp->f_flag |= FNONBLOCK;
5501541Srgrimes		else
5511541Srgrimes			fp->f_flag &= ~FNONBLOCK;
5521541Srgrimes		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
5531541Srgrimes		break;
5541541Srgrimes
5551541Srgrimes	case FIOASYNC:
5563098Sphk		if ((tmp = *(int *)data))
5571541Srgrimes			fp->f_flag |= FASYNC;
5581541Srgrimes		else
5591541Srgrimes			fp->f_flag &= ~FASYNC;
5601541Srgrimes		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
5611541Srgrimes		break;
5621541Srgrimes
5631541Srgrimes	default:
5641541Srgrimes		error = (*fp->f_ops->fo_ioctl)(fp, com, data, p);
5651541Srgrimes		/*
5661541Srgrimes		 * Copy any data to user, size was
5671541Srgrimes		 * already set and checked above.
5681541Srgrimes		 */
5691541Srgrimes		if (error == 0 && (com&IOC_OUT) && size)
5701541Srgrimes			error = copyout(data, uap->data, (u_int)size);
5711541Srgrimes		break;
5721541Srgrimes	}
5731541Srgrimes	if (memp)
5741541Srgrimes		free(memp, M_IOCTLOPS);
5751541Srgrimes	return (error);
5761541Srgrimes}
5771541Srgrimes
57812819Sphkstatic int	nselcoll;
57912819Sphkint	selwait;
5801541Srgrimes
5811541Srgrimes/*
5821541Srgrimes * Select system call.
5831541Srgrimes */
58412221Sbde#ifndef _SYS_SYSPROTO_H_
5851541Srgrimesstruct select_args {
58617702Ssmpatel	int	nd;
5871541Srgrimes	fd_set	*in, *ou, *ex;
5881541Srgrimes	struct	timeval *tv;
5891541Srgrimes};
59012221Sbde#endif
5911549Srgrimesint
59230994Sphkselect(p, uap)
5931541Srgrimes	register struct proc *p;
5941541Srgrimes	register struct select_args *uap;
5951541Srgrimes{
59622945Sbde	/*
59722945Sbde	 * The magic 2048 here is chosen to be just enough for FD_SETSIZE
59822945Sbde	 * infds with the new FD_SETSIZE of 1024, and more than enough for
59922945Sbde	 * FD_SETSIZE infds, outfds and exceptfds with the old FD_SETSIZE
60022945Sbde	 * of 256.
60122945Sbde	 */
60222945Sbde	fd_mask s_selbits[howmany(2048, NFDBITS)];
60322945Sbde	fd_mask *ibits[3], *obits[3], *selbits, *sbp;
60435029Sphk	struct timeval atv, rtv, ttv;
60535029Sphk	int s, ncoll, error, timo;
60622945Sbde	u_int nbufbytes, ncpbytes, nfdbits;
6071541Srgrimes
60817702Ssmpatel	if (uap->nd < 0)
60917713Ssmpatel		return (EINVAL);
6101541Srgrimes	if (uap->nd > p->p_fd->fd_nfiles)
61117702Ssmpatel		uap->nd = p->p_fd->fd_nfiles;   /* forgiving; slightly wrong */
61217702Ssmpatel
61322945Sbde	/*
61422945Sbde	 * Allocate just enough bits for the non-null fd_sets.  Use the
61522945Sbde	 * preallocated auto buffer if possible.
61622945Sbde	 */
61722945Sbde	nfdbits = roundup(uap->nd, NFDBITS);
61822945Sbde	ncpbytes = nfdbits / NBBY;
61922945Sbde	nbufbytes = 0;
62022945Sbde	if (uap->in != NULL)
62122945Sbde		nbufbytes += 2 * ncpbytes;
62222945Sbde	if (uap->ou != NULL)
62322945Sbde		nbufbytes += 2 * ncpbytes;
62422945Sbde	if (uap->ex != NULL)
62522945Sbde		nbufbytes += 2 * ncpbytes;
62622945Sbde	if (nbufbytes <= sizeof s_selbits)
62722945Sbde		selbits = &s_selbits[0];
62822945Sbde	else
62922945Sbde		selbits = malloc(nbufbytes, M_SELECT, M_WAITOK);
63017702Ssmpatel
63117702Ssmpatel	/*
63222945Sbde	 * Assign pointers into the bit buffers and fetch the input bits.
63322945Sbde	 * Put the output buffers together so that they can be bzeroed
63422945Sbde	 * together.
63517702Ssmpatel	 */
63622945Sbde	sbp = selbits;
6371541Srgrimes#define	getbits(name, x) \
63822945Sbde	do {								\
63922945Sbde		if (uap->name == NULL)					\
64022945Sbde			ibits[x] = NULL;				\
64122945Sbde		else {							\
64222945Sbde			ibits[x] = sbp + nbufbytes / 2 / sizeof *sbp;	\
64322945Sbde			obits[x] = sbp;					\
64422945Sbde			sbp += ncpbytes / sizeof *sbp;			\
64522945Sbde			error = copyin(uap->name, ibits[x], ncpbytes);	\
64622945Sbde			if (error != 0)					\
64722945Sbde				goto done;				\
64822945Sbde		}							\
64922945Sbde	} while (0)
6501541Srgrimes	getbits(in, 0);
6511541Srgrimes	getbits(ou, 1);
6521541Srgrimes	getbits(ex, 2);
6531541Srgrimes#undef	getbits
65422945Sbde	if (nbufbytes != 0)
65522945Sbde		bzero(selbits, nbufbytes / 2);
6561541Srgrimes
6571541Srgrimes	if (uap->tv) {
6581541Srgrimes		error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
6591541Srgrimes			sizeof (atv));
6601541Srgrimes		if (error)
6611541Srgrimes			goto done;
6621541Srgrimes		if (itimerfix(&atv)) {
6631541Srgrimes			error = EINVAL;
6641541Srgrimes			goto done;
6651541Srgrimes		}
66636119Sphk		getmicrouptime(&rtv);
66735029Sphk		timevaladd(&atv, &rtv);
66835041Sache	} else
66935029Sphk		atv.tv_sec = 0;
67035029Sphk	timo = 0;
6711541Srgrimesretry:
6721541Srgrimes	ncoll = nselcoll;
6731541Srgrimes	p->p_flag |= P_SELECT;
67430994Sphk	error = selscan(p, ibits, obits, uap->nd);
67530994Sphk	if (error || p->p_retval[0])
6761541Srgrimes		goto done;
67735029Sphk	if (atv.tv_sec) {
67836119Sphk		getmicrouptime(&rtv);
67935029Sphk		if (timevalcmp(&rtv, &atv, >=))
68035029Sphk			goto done;
68135029Sphk		ttv = atv;
68235029Sphk		timevalsub(&ttv, &rtv);
68335029Sphk		timo = ttv.tv_sec > 24 * 60 * 60 ?
68435029Sphk		    24 * 60 * 60 * hz : tvtohz(&ttv);
68535029Sphk	}
6861541Srgrimes	s = splhigh();
6871541Srgrimes	if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
6881541Srgrimes		splx(s);
6891541Srgrimes		goto retry;
6901541Srgrimes	}
6911541Srgrimes	p->p_flag &= ~P_SELECT;
6921541Srgrimes	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "select", timo);
6931541Srgrimes	splx(s);
6941541Srgrimes	if (error == 0)
6951541Srgrimes		goto retry;
6961541Srgrimesdone:
6971541Srgrimes	p->p_flag &= ~P_SELECT;
6981541Srgrimes	/* select is not restarted after signals... */
6991541Srgrimes	if (error == ERESTART)
7001541Srgrimes		error = EINTR;
7011541Srgrimes	if (error == EWOULDBLOCK)
7021541Srgrimes		error = 0;
7031541Srgrimes#define	putbits(name, x) \
70422945Sbde	if (uap->name && (error2 = copyout(obits[x], uap->name, ncpbytes))) \
7051541Srgrimes		error = error2;
7061541Srgrimes	if (error == 0) {
7071541Srgrimes		int error2;
7081541Srgrimes
7091541Srgrimes		putbits(in, 0);
7101541Srgrimes		putbits(ou, 1);
7111541Srgrimes		putbits(ex, 2);
7121541Srgrimes#undef putbits
7131541Srgrimes	}
71422945Sbde	if (selbits != &s_selbits[0])
71522945Sbde		free(selbits, M_SELECT);
7161541Srgrimes	return (error);
7171541Srgrimes}
7181541Srgrimes
71912819Sphkstatic int
72030994Sphkselscan(p, ibits, obits, nfd)
7211541Srgrimes	struct proc *p;
72217702Ssmpatel	fd_mask **ibits, **obits;
72330994Sphk	int nfd;
7241541Srgrimes{
7251541Srgrimes	register struct filedesc *fdp = p->p_fd;
7261541Srgrimes	register int msk, i, j, fd;
7271541Srgrimes	register fd_mask bits;
7281541Srgrimes	struct file *fp;
7291541Srgrimes	int n = 0;
73031364Sbde	/* Note: backend also returns POLLHUP/POLLERR if appropriate. */
73131364Sbde	static int flag[3] = { POLLRDNORM, POLLWRNORM, POLLRDBAND };
7321541Srgrimes
7331541Srgrimes	for (msk = 0; msk < 3; msk++) {
73422945Sbde		if (ibits[msk] == NULL)
73522945Sbde			continue;
7361541Srgrimes		for (i = 0; i < nfd; i += NFDBITS) {
73717702Ssmpatel			bits = ibits[msk][i/NFDBITS];
7381541Srgrimes			while ((j = ffs(bits)) && (fd = i + --j) < nfd) {
7391541Srgrimes				bits &= ~(1 << j);
7401541Srgrimes				fp = fdp->fd_ofiles[fd];
7411541Srgrimes				if (fp == NULL)
7421541Srgrimes					return (EBADF);
74329351Speter				if ((*fp->f_ops->fo_poll)(fp, flag[msk],
74429351Speter				    fp->f_cred, p)) {
74522945Sbde					obits[msk][(fd)/NFDBITS] |=
74617702Ssmpatel						(1 << ((fd) % NFDBITS));
7471541Srgrimes					n++;
7481541Srgrimes				}
7491541Srgrimes			}
7501541Srgrimes		}
7511541Srgrimes	}
75230994Sphk	p->p_retval[0] = n;
7531541Srgrimes	return (0);
7541541Srgrimes}
7551541Srgrimes
75629351Speter/*
75729351Speter * Poll system call.
75829351Speter */
75929351Speter#ifndef _SYS_SYSPROTO_H_
76029351Speterstruct poll_args {
76129351Speter	struct pollfd *fds;
76229351Speter	u_int	nfds;
76329351Speter	int	timeout;
76429351Speter};
76529351Speter#endif
76629351Speterint
76730994Sphkpoll(p, uap)
76829351Speter	register struct proc *p;
76929351Speter	register struct poll_args *uap;
77029351Speter{
77129351Speter	caddr_t bits;
77229351Speter	char smallbits[32 * sizeof(struct pollfd)];
77335029Sphk	struct timeval atv, rtv, ttv;
77435029Sphk	int s, ncoll, error = 0, timo;
77529351Speter	size_t ni;
77629351Speter
77729351Speter	if (SCARG(uap, nfds) > p->p_fd->fd_nfiles) {
77829351Speter		/* forgiving; slightly wrong */
77929351Speter		SCARG(uap, nfds) = p->p_fd->fd_nfiles;
78029351Speter	}
78129351Speter	ni = SCARG(uap, nfds) * sizeof(struct pollfd);
78229351Speter	if (ni > sizeof(smallbits))
78329351Speter		bits = malloc(ni, M_TEMP, M_WAITOK);
78429351Speter	else
78529351Speter		bits = smallbits;
78629351Speter	error = copyin(SCARG(uap, fds), bits, ni);
78729351Speter	if (error)
78829351Speter		goto done;
78929351Speter	if (SCARG(uap, timeout) != INFTIM) {
79029351Speter		atv.tv_sec = SCARG(uap, timeout) / 1000;
79129351Speter		atv.tv_usec = (SCARG(uap, timeout) % 1000) * 1000;
79229351Speter		if (itimerfix(&atv)) {
79329351Speter			error = EINVAL;
79429351Speter			goto done;
79529351Speter		}
79636119Sphk		getmicrouptime(&rtv);
79735029Sphk		timevaladd(&atv, &rtv);
79835041Sache	} else
79935029Sphk		atv.tv_sec = 0;
80035029Sphk	timo = 0;
80129351Speterretry:
80229351Speter	ncoll = nselcoll;
80329351Speter	p->p_flag |= P_SELECT;
80430994Sphk	error = pollscan(p, (struct pollfd *)bits, SCARG(uap, nfds));
80530994Sphk	if (error || p->p_retval[0])
80629351Speter		goto done;
80735029Sphk	if (atv.tv_sec) {
80836119Sphk		getmicrouptime(&rtv);
80935029Sphk		if (timevalcmp(&rtv, &atv, >=))
81035029Sphk			goto done;
81135029Sphk		ttv = atv;
81235029Sphk		timevalsub(&ttv, &rtv);
81335029Sphk		timo = ttv.tv_sec > 24 * 60 * 60 ?
81435029Sphk		    24 * 60 * 60 * hz : tvtohz(&ttv);
81535029Sphk	}
81634961Sphk	s = splhigh();
81729351Speter	if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) {
81829351Speter		splx(s);
81929351Speter		goto retry;
82029351Speter	}
82129351Speter	p->p_flag &= ~P_SELECT;
82229351Speter	error = tsleep((caddr_t)&selwait, PSOCK | PCATCH, "poll", timo);
82329351Speter	splx(s);
82429351Speter	if (error == 0)
82529351Speter		goto retry;
82629351Speterdone:
82729351Speter	p->p_flag &= ~P_SELECT;
82829351Speter	/* poll is not restarted after signals... */
82929351Speter	if (error == ERESTART)
83029351Speter		error = EINTR;
83129351Speter	if (error == EWOULDBLOCK)
83229351Speter		error = 0;
83329351Speter	if (error == 0) {
83429351Speter		error = copyout(bits, SCARG(uap, fds), ni);
83529351Speter		if (error)
83629351Speter			goto out;
83729351Speter	}
83829351Speterout:
83929351Speter	if (ni > sizeof(smallbits))
84029351Speter		free(bits, M_TEMP);
84129351Speter	return (error);
84229351Speter}
84329351Speter
84429351Speterstatic int
84530994Sphkpollscan(p, fds, nfd)
84629351Speter	struct proc *p;
84729351Speter	struct pollfd *fds;
84829351Speter	int nfd;
84929351Speter{
85029351Speter	register struct filedesc *fdp = p->p_fd;
85129351Speter	int i;
85229351Speter	struct file *fp;
85329351Speter	int n = 0;
85429351Speter
85529351Speter	for (i = 0; i < nfd; i++, fds++) {
85641632Sjkh		if (fds->fd >= fdp->fd_nfiles) {
85729351Speter			fds->revents = POLLNVAL;
85829351Speter			n++;
85941632Sjkh		} else if (fds->fd < 0) {
86041632Sjkh			fds->revents = 0;
86129351Speter		} else {
86229351Speter			fp = fdp->fd_ofiles[fds->fd];
86329351Speter			if (fp == 0) {
86429351Speter				fds->revents = POLLNVAL;
86529351Speter				n++;
86629351Speter			} else {
86731364Sbde				/*
86831364Sbde				 * Note: backend also returns POLLHUP and
86931364Sbde				 * POLLERR if appropriate.
87031364Sbde				 */
87129351Speter				fds->revents = (*fp->f_ops->fo_poll)(fp,
87229351Speter				    fds->events, fp->f_cred, p);
87329351Speter				if (fds->revents != 0)
87429351Speter					n++;
87529351Speter			}
87629351Speter		}
87729351Speter	}
87830994Sphk	p->p_retval[0] = n;
87929351Speter	return (0);
88029351Speter}
88129351Speter
88229351Speter/*
88329351Speter * OpenBSD poll system call.
88429351Speter * XXX this isn't quite a true representation..  OpenBSD uses select ops.
88529351Speter */
88629351Speter#ifndef _SYS_SYSPROTO_H_
88729351Speterstruct openbsd_poll_args {
88829351Speter	struct pollfd *fds;
88929351Speter	u_int	nfds;
89029351Speter	int	timeout;
89129351Speter};
89229351Speter#endif
89329351Speterint
89430994Sphkopenbsd_poll(p, uap)
89529351Speter	register struct proc *p;
89629351Speter	register struct openbsd_poll_args *uap;
89729351Speter{
89830994Sphk	return (poll(p, (struct poll_args *)uap));
89929351Speter}
90029351Speter
9011541Srgrimes/*ARGSUSED*/
9021549Srgrimesint
90329351Speterseltrue(dev, events, p)
9041541Srgrimes	dev_t dev;
90529351Speter	int events;
9061541Srgrimes	struct proc *p;
9071541Srgrimes{
9081541Srgrimes
90929351Speter	return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
9101541Srgrimes}
9111541Srgrimes
9121541Srgrimes/*
9131541Srgrimes * Record a select request.
9141541Srgrimes */
9151541Srgrimesvoid
9161541Srgrimesselrecord(selector, sip)
9171541Srgrimes	struct proc *selector;
9181541Srgrimes	struct selinfo *sip;
9191541Srgrimes{
9201541Srgrimes	struct proc *p;
9211541Srgrimes	pid_t mypid;
9221541Srgrimes
9231541Srgrimes	mypid = selector->p_pid;
9241541Srgrimes	if (sip->si_pid == mypid)
9251541Srgrimes		return;
9261541Srgrimes	if (sip->si_pid && (p = pfind(sip->si_pid)) &&
9271541Srgrimes	    p->p_wchan == (caddr_t)&selwait)
9281541Srgrimes		sip->si_flags |= SI_COLL;
9291541Srgrimes	else
9301541Srgrimes		sip->si_pid = mypid;
9311541Srgrimes}
9321541Srgrimes
9331541Srgrimes/*
9341541Srgrimes * Do a wakeup when a selectable event occurs.
9351541Srgrimes */
9361541Srgrimesvoid
9371541Srgrimesselwakeup(sip)
9381541Srgrimes	register struct selinfo *sip;
9391541Srgrimes{
9401541Srgrimes	register struct proc *p;
9411541Srgrimes	int s;
9421541Srgrimes
9431541Srgrimes	if (sip->si_pid == 0)
9441541Srgrimes		return;
9451541Srgrimes	if (sip->si_flags & SI_COLL) {
9461541Srgrimes		nselcoll++;
9471541Srgrimes		sip->si_flags &= ~SI_COLL;
9481541Srgrimes		wakeup((caddr_t)&selwait);
9491541Srgrimes	}
9501541Srgrimes	p = pfind(sip->si_pid);
9511541Srgrimes	sip->si_pid = 0;
9521541Srgrimes	if (p != NULL) {
9531541Srgrimes		s = splhigh();
9541541Srgrimes		if (p->p_wchan == (caddr_t)&selwait) {
9551541Srgrimes			if (p->p_stat == SSLEEP)
9561541Srgrimes				setrunnable(p);
9571541Srgrimes			else
9581541Srgrimes				unsleep(p);
9591541Srgrimes		} else if (p->p_flag & P_SELECT)
9601541Srgrimes			p->p_flag &= ~P_SELECT;
9611541Srgrimes		splx(s);
9621541Srgrimes	}
9631541Srgrimes}
964