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