Home | History | Annotate | Line # | Download | only in kern
sys_generic.c revision 1.83.2.9
      1  1.83.2.9      yamt /*	$NetBSD: sys_generic.c,v 1.83.2.9 2008/03/24 09:39:02 yamt Exp $	*/
      2  1.83.2.4      yamt 
      3  1.83.2.4      yamt /*-
      4  1.83.2.8      yamt  * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc.
      5  1.83.2.4      yamt  * All rights reserved.
      6  1.83.2.4      yamt  *
      7  1.83.2.4      yamt  * This code is derived from software contributed to The NetBSD Foundation
      8  1.83.2.4      yamt  * by Andrew Doran.
      9  1.83.2.4      yamt  *
     10  1.83.2.4      yamt  * Redistribution and use in source and binary forms, with or without
     11  1.83.2.4      yamt  * modification, are permitted provided that the following conditions
     12  1.83.2.4      yamt  * are met:
     13  1.83.2.4      yamt  * 1. Redistributions of source code must retain the above copyright
     14  1.83.2.4      yamt  *    notice, this list of conditions and the following disclaimer.
     15  1.83.2.4      yamt  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.83.2.4      yamt  *    notice, this list of conditions and the following disclaimer in the
     17  1.83.2.4      yamt  *    documentation and/or other materials provided with the distribution.
     18  1.83.2.4      yamt  * 3. All advertising materials mentioning features or use of this software
     19  1.83.2.4      yamt  *    must display the following acknowledgement:
     20  1.83.2.4      yamt  *	This product includes software developed by the NetBSD
     21  1.83.2.4      yamt  *	Foundation, Inc. and its contributors.
     22  1.83.2.4      yamt  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  1.83.2.4      yamt  *    contributors may be used to endorse or promote products derived
     24  1.83.2.4      yamt  *    from this software without specific prior written permission.
     25  1.83.2.4      yamt  *
     26  1.83.2.4      yamt  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  1.83.2.4      yamt  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  1.83.2.4      yamt  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  1.83.2.4      yamt  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  1.83.2.4      yamt  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  1.83.2.4      yamt  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  1.83.2.4      yamt  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  1.83.2.4      yamt  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  1.83.2.4      yamt  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  1.83.2.4      yamt  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  1.83.2.4      yamt  * POSSIBILITY OF SUCH DAMAGE.
     37  1.83.2.4      yamt  */
     38      1.15       cgd 
     39      1.15       cgd /*
     40      1.15       cgd  * Copyright (c) 1982, 1986, 1989, 1993
     41      1.15       cgd  *	The Regents of the University of California.  All rights reserved.
     42      1.15       cgd  * (c) UNIX System Laboratories, Inc.
     43      1.15       cgd  * All or some portions of this file are derived from material licensed
     44      1.15       cgd  * to the University of California by American Telephone and Telegraph
     45      1.15       cgd  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     46      1.15       cgd  * the permission of UNIX System Laboratories, Inc.
     47      1.15       cgd  *
     48      1.15       cgd  * Redistribution and use in source and binary forms, with or without
     49      1.15       cgd  * modification, are permitted provided that the following conditions
     50      1.15       cgd  * are met:
     51      1.15       cgd  * 1. Redistributions of source code must retain the above copyright
     52      1.15       cgd  *    notice, this list of conditions and the following disclaimer.
     53      1.15       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     54      1.15       cgd  *    notice, this list of conditions and the following disclaimer in the
     55      1.15       cgd  *    documentation and/or other materials provided with the distribution.
     56      1.77       agc  * 3. Neither the name of the University nor the names of its contributors
     57      1.15       cgd  *    may be used to endorse or promote products derived from this software
     58      1.15       cgd  *    without specific prior written permission.
     59      1.15       cgd  *
     60      1.15       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     61      1.15       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     62      1.15       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     63      1.15       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     64      1.15       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     65      1.15       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     66      1.15       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     67      1.15       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     68      1.15       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     69      1.15       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     70      1.15       cgd  * SUCH DAMAGE.
     71      1.15       cgd  *
     72      1.36      fvdl  *	@(#)sys_generic.c	8.9 (Berkeley) 2/14/95
     73      1.15       cgd  */
     74      1.59     lukem 
     75  1.83.2.4      yamt /*
     76  1.83.2.4      yamt  * System calls relating to files.
     77  1.83.2.4      yamt  */
     78      1.37   thorpej 
     79  1.83.2.4      yamt #include <sys/cdefs.h>
     80  1.83.2.9      yamt __KERNEL_RCSID(0, "$NetBSD: sys_generic.c,v 1.83.2.9 2008/03/24 09:39:02 yamt Exp $");
     81      1.15       cgd 
     82      1.15       cgd #include <sys/param.h>
     83      1.15       cgd #include <sys/systm.h>
     84      1.15       cgd #include <sys/filedesc.h>
     85      1.15       cgd #include <sys/ioctl.h>
     86      1.15       cgd #include <sys/file.h>
     87      1.15       cgd #include <sys/proc.h>
     88      1.15       cgd #include <sys/socketvar.h>
     89      1.22  christos #include <sys/signalvar.h>
     90      1.15       cgd #include <sys/uio.h>
     91      1.15       cgd #include <sys/kernel.h>
     92      1.15       cgd #include <sys/stat.h>
     93  1.83.2.4      yamt #include <sys/kmem.h>
     94      1.28   mycroft #include <sys/poll.h>
     95  1.83.2.4      yamt #include <sys/vnode.h>
     96      1.16       cgd #include <sys/mount.h>
     97      1.16       cgd #include <sys/syscallargs.h>
     98  1.83.2.4      yamt #include <sys/ktrace.h>
     99      1.22  christos 
    100  1.83.2.1      yamt #include <uvm/uvm_extern.h>
    101  1.83.2.1      yamt 
    102      1.15       cgd /*
    103      1.15       cgd  * Read system call.
    104      1.15       cgd  */
    105      1.15       cgd /* ARGSUSED */
    106      1.22  christos int
    107  1.83.2.7      yamt sys_read(struct lwp *l, const struct sys_read_args *uap, register_t *retval)
    108      1.20   thorpej {
    109  1.83.2.7      yamt 	/* {
    110      1.53     lukem 		syscallarg(int)		fd;
    111      1.53     lukem 		syscallarg(void *)	buf;
    112      1.53     lukem 		syscallarg(size_t)	nbyte;
    113  1.83.2.7      yamt 	} */
    114  1.83.2.9      yamt 	file_t *fp;
    115  1.83.2.9      yamt 	int fd;
    116      1.39   thorpej 
    117      1.53     lukem 	fd = SCARG(uap, fd);
    118      1.56   thorpej 
    119  1.83.2.9      yamt 	if ((fp = fd_getfile(fd)) == NULL)
    120      1.56   thorpej 		return (EBADF);
    121      1.56   thorpej 
    122      1.70        pk 	if ((fp->f_flag & FREAD) == 0) {
    123  1.83.2.9      yamt 		fd_putfile(fd);
    124      1.39   thorpej 		return (EBADF);
    125      1.70        pk 	}
    126      1.39   thorpej 
    127      1.45   thorpej 	/* dofileread() will unuse the descriptor for us */
    128  1.83.2.5      yamt 	return (dofileread(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
    129      1.39   thorpej 	    &fp->f_offset, FOF_UPDATE_OFFSET, retval));
    130      1.39   thorpej }
    131      1.39   thorpej 
    132      1.39   thorpej int
    133  1.83.2.5      yamt dofileread(int fd, struct file *fp, void *buf, size_t nbyte,
    134      1.53     lukem 	off_t *offset, int flags, register_t *retval)
    135      1.53     lukem {
    136  1.83.2.1      yamt 	struct iovec aiov;
    137  1.83.2.1      yamt 	struct uio auio;
    138  1.83.2.1      yamt 	size_t cnt;
    139  1.83.2.1      yamt 	int error;
    140  1.83.2.5      yamt 	lwp_t *l;
    141  1.83.2.1      yamt 
    142  1.83.2.5      yamt 	l = curlwp;
    143      1.15       cgd 
    144  1.83.2.4      yamt 	aiov.iov_base = (void *)buf;
    145      1.39   thorpej 	aiov.iov_len = nbyte;
    146      1.15       cgd 	auio.uio_iov = &aiov;
    147      1.15       cgd 	auio.uio_iovcnt = 1;
    148      1.39   thorpej 	auio.uio_resid = nbyte;
    149      1.15       cgd 	auio.uio_rw = UIO_READ;
    150  1.83.2.5      yamt 	auio.uio_vmspace = l->l_proc->p_vmspace;
    151      1.40   thorpej 
    152      1.40   thorpej 	/*
    153      1.40   thorpej 	 * Reads return ssize_t because -1 is returned on error.  Therefore
    154      1.40   thorpej 	 * we must restrict the length to SSIZE_MAX to avoid garbage return
    155      1.40   thorpej 	 * values.
    156      1.40   thorpej 	 */
    157      1.45   thorpej 	if (auio.uio_resid > SSIZE_MAX) {
    158      1.45   thorpej 		error = EINVAL;
    159      1.45   thorpej 		goto out;
    160      1.45   thorpej 	}
    161      1.40   thorpej 
    162      1.38   thorpej 	cnt = auio.uio_resid;
    163      1.39   thorpej 	error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags);
    164      1.22  christos 	if (error)
    165      1.15       cgd 		if (auio.uio_resid != cnt && (error == ERESTART ||
    166      1.15       cgd 		    error == EINTR || error == EWOULDBLOCK))
    167      1.15       cgd 			error = 0;
    168      1.15       cgd 	cnt -= auio.uio_resid;
    169  1.83.2.4      yamt 	ktrgenio(fd, UIO_READ, buf, cnt, error);
    170      1.15       cgd 	*retval = cnt;
    171      1.45   thorpej  out:
    172  1.83.2.9      yamt 	fd_putfile(fd);
    173      1.15       cgd 	return (error);
    174      1.15       cgd }
    175      1.15       cgd 
    176      1.15       cgd /*
    177      1.15       cgd  * Scatter read system call.
    178      1.15       cgd  */
    179      1.22  christos int
    180  1.83.2.7      yamt sys_readv(struct lwp *l, const struct sys_readv_args *uap, register_t *retval)
    181      1.20   thorpej {
    182  1.83.2.7      yamt 	/* {
    183      1.53     lukem 		syscallarg(int)				fd;
    184      1.53     lukem 		syscallarg(const struct iovec *)	iovp;
    185      1.53     lukem 		syscallarg(int)				iovcnt;
    186  1.83.2.7      yamt 	} */
    187  1.83.2.4      yamt 
    188  1.83.2.5      yamt 	return do_filereadv(SCARG(uap, fd), SCARG(uap, iovp),
    189  1.83.2.4      yamt 	    SCARG(uap, iovcnt), NULL, FOF_UPDATE_OFFSET, retval);
    190  1.83.2.4      yamt }
    191  1.83.2.4      yamt 
    192  1.83.2.4      yamt int
    193  1.83.2.5      yamt do_filereadv(int fd, const struct iovec *iovp, int iovcnt,
    194  1.83.2.4      yamt     off_t *offset, int flags, register_t *retval)
    195  1.83.2.4      yamt {
    196  1.83.2.4      yamt 	struct uio	auio;
    197  1.83.2.4      yamt 	struct iovec	*iov, *needfree = NULL, aiov[UIO_SMALLIOV];
    198  1.83.2.4      yamt 	int		i, error;
    199  1.83.2.4      yamt 	size_t		cnt;
    200  1.83.2.4      yamt 	u_int		iovlen;
    201  1.83.2.4      yamt 	struct file	*fp;
    202  1.83.2.4      yamt 	struct iovec	*ktriov = NULL;
    203  1.83.2.4      yamt 
    204  1.83.2.4      yamt 	if (iovcnt == 0)
    205  1.83.2.4      yamt 		return EINVAL;
    206      1.39   thorpej 
    207  1.83.2.9      yamt 	if ((fp = fd_getfile(fd)) == NULL)
    208  1.83.2.4      yamt 		return EBADF;
    209      1.56   thorpej 
    210      1.70        pk 	if ((fp->f_flag & FREAD) == 0) {
    211  1.83.2.9      yamt 		fd_putfile(fd);
    212  1.83.2.4      yamt 		return EBADF;
    213      1.70        pk 	}
    214      1.39   thorpej 
    215  1.83.2.4      yamt 	if (offset == NULL)
    216  1.83.2.4      yamt 		offset = &fp->f_offset;
    217  1.83.2.4      yamt 	else {
    218  1.83.2.4      yamt 		struct vnode *vp = fp->f_data;
    219  1.83.2.4      yamt 		if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
    220  1.83.2.4      yamt 			error = ESPIPE;
    221  1.83.2.4      yamt 			goto out;
    222  1.83.2.4      yamt 		}
    223  1.83.2.4      yamt 		/*
    224  1.83.2.4      yamt 		 * Test that the device is seekable ?
    225  1.83.2.4      yamt 		 * XXX This works because no file systems actually
    226  1.83.2.4      yamt 		 * XXX take any action on the seek operation.
    227  1.83.2.4      yamt 		 */
    228  1.83.2.4      yamt 		error = VOP_SEEK(vp, fp->f_offset, *offset, fp->f_cred);
    229  1.83.2.4      yamt 		if (error != 0)
    230  1.83.2.4      yamt 			goto out;
    231  1.83.2.4      yamt 	}
    232      1.15       cgd 
    233      1.42     perry 	iovlen = iovcnt * sizeof(struct iovec);
    234  1.83.2.4      yamt 	if (flags & FOF_IOV_SYSSPACE)
    235  1.83.2.4      yamt 		iov = __UNCONST(iovp);
    236  1.83.2.4      yamt 	else {
    237      1.15       cgd 		iov = aiov;
    238  1.83.2.4      yamt 		if ((u_int)iovcnt > UIO_SMALLIOV) {
    239  1.83.2.4      yamt 			if ((u_int)iovcnt > IOV_MAX) {
    240  1.83.2.4      yamt 				error = EINVAL;
    241  1.83.2.4      yamt 				goto out;
    242  1.83.2.4      yamt 			}
    243  1.83.2.4      yamt 			iov = kmem_alloc(iovlen, KM_SLEEP);
    244  1.83.2.4      yamt 			if (iov == NULL) {
    245  1.83.2.4      yamt 				error = ENOMEM;
    246  1.83.2.4      yamt 				goto out;
    247  1.83.2.4      yamt 			}
    248  1.83.2.4      yamt 			needfree = iov;
    249  1.83.2.4      yamt 		}
    250  1.83.2.4      yamt 		error = copyin(iovp, iov, iovlen);
    251  1.83.2.4      yamt 		if (error)
    252  1.83.2.4      yamt 			goto done;
    253      1.45   thorpej 	}
    254      1.41    kleink 
    255      1.15       cgd 	auio.uio_iov = iov;
    256      1.34   mycroft 	auio.uio_iovcnt = iovcnt;
    257      1.15       cgd 	auio.uio_rw = UIO_READ;
    258  1.83.2.9      yamt 	auio.uio_vmspace = curproc->p_vmspace;
    259  1.83.2.4      yamt 
    260      1.15       cgd 	auio.uio_resid = 0;
    261  1.83.2.4      yamt 	for (i = 0; i < iovcnt; i++, iov++) {
    262      1.15       cgd 		auio.uio_resid += iov->iov_len;
    263      1.40   thorpej 		/*
    264      1.40   thorpej 		 * Reads return ssize_t because -1 is returned on error.
    265      1.40   thorpej 		 * Therefore we must restrict the length to SSIZE_MAX to
    266      1.40   thorpej 		 * avoid garbage return values.
    267      1.40   thorpej 		 */
    268      1.40   thorpej 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
    269      1.15       cgd 			error = EINVAL;
    270      1.15       cgd 			goto done;
    271      1.15       cgd 		}
    272      1.15       cgd 	}
    273  1.83.2.4      yamt 
    274      1.15       cgd 	/*
    275      1.15       cgd 	 * if tracing, save a copy of iovec
    276      1.15       cgd 	 */
    277  1.83.2.4      yamt 	if (ktrpoint(KTR_GENIO))  {
    278  1.83.2.4      yamt 		ktriov = kmem_alloc(iovlen, KM_SLEEP);
    279  1.83.2.4      yamt 		if (ktriov != NULL)
    280  1.83.2.4      yamt 			memcpy(ktriov, auio.uio_iov, iovlen);
    281      1.15       cgd 	}
    282  1.83.2.4      yamt 
    283      1.15       cgd 	cnt = auio.uio_resid;
    284      1.39   thorpej 	error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags);
    285      1.22  christos 	if (error)
    286      1.15       cgd 		if (auio.uio_resid != cnt && (error == ERESTART ||
    287      1.15       cgd 		    error == EINTR || error == EWOULDBLOCK))
    288      1.15       cgd 			error = 0;
    289      1.15       cgd 	cnt -= auio.uio_resid;
    290  1.83.2.4      yamt 	*retval = cnt;
    291  1.83.2.4      yamt 
    292      1.58     itohy 	if (ktriov != NULL) {
    293  1.83.2.4      yamt 		ktrgeniov(fd, UIO_READ, ktriov, cnt, error);
    294  1.83.2.4      yamt 		kmem_free(ktriov, iovlen);
    295      1.15       cgd 	}
    296  1.83.2.4      yamt 
    297      1.45   thorpej  done:
    298      1.15       cgd 	if (needfree)
    299  1.83.2.4      yamt 		kmem_free(needfree, iovlen);
    300      1.45   thorpej  out:
    301  1.83.2.9      yamt 	fd_putfile(fd);
    302      1.15       cgd 	return (error);
    303      1.15       cgd }
    304      1.15       cgd 
    305      1.15       cgd /*
    306      1.15       cgd  * Write system call
    307      1.15       cgd  */
    308      1.22  christos int
    309  1.83.2.7      yamt sys_write(struct lwp *l, const struct sys_write_args *uap, register_t *retval)
    310      1.20   thorpej {
    311  1.83.2.7      yamt 	/* {
    312      1.53     lukem 		syscallarg(int)			fd;
    313      1.53     lukem 		syscallarg(const void *)	buf;
    314      1.53     lukem 		syscallarg(size_t)		nbyte;
    315  1.83.2.7      yamt 	} */
    316  1.83.2.9      yamt 	file_t *fp;
    317  1.83.2.9      yamt 	int fd;
    318      1.39   thorpej 
    319      1.53     lukem 	fd = SCARG(uap, fd);
    320      1.56   thorpej 
    321  1.83.2.9      yamt 	if ((fp = fd_getfile(fd)) == NULL)
    322      1.56   thorpej 		return (EBADF);
    323      1.56   thorpej 
    324      1.70        pk 	if ((fp->f_flag & FWRITE) == 0) {
    325  1.83.2.9      yamt 		fd_putfile(fd);
    326      1.39   thorpej 		return (EBADF);
    327      1.70        pk 	}
    328      1.39   thorpej 
    329      1.45   thorpej 	/* dofilewrite() will unuse the descriptor for us */
    330  1.83.2.5      yamt 	return (dofilewrite(fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
    331      1.39   thorpej 	    &fp->f_offset, FOF_UPDATE_OFFSET, retval));
    332      1.39   thorpej }
    333      1.39   thorpej 
    334      1.39   thorpej int
    335  1.83.2.5      yamt dofilewrite(int fd, struct file *fp, const void *buf,
    336      1.53     lukem 	size_t nbyte, off_t *offset, int flags, register_t *retval)
    337      1.53     lukem {
    338  1.83.2.1      yamt 	struct iovec aiov;
    339  1.83.2.1      yamt 	struct uio auio;
    340  1.83.2.1      yamt 	size_t cnt;
    341  1.83.2.1      yamt 	int error;
    342      1.15       cgd 
    343      1.83  christos 	aiov.iov_base = __UNCONST(buf);		/* XXXUNCONST kills const */
    344      1.39   thorpej 	aiov.iov_len = nbyte;
    345      1.15       cgd 	auio.uio_iov = &aiov;
    346      1.15       cgd 	auio.uio_iovcnt = 1;
    347      1.39   thorpej 	auio.uio_resid = nbyte;
    348      1.15       cgd 	auio.uio_rw = UIO_WRITE;
    349  1.83.2.9      yamt 	auio.uio_vmspace = curproc->p_vmspace;
    350      1.40   thorpej 
    351      1.40   thorpej 	/*
    352      1.40   thorpej 	 * Writes return ssize_t because -1 is returned on error.  Therefore
    353      1.40   thorpej 	 * we must restrict the length to SSIZE_MAX to avoid garbage return
    354      1.40   thorpej 	 * values.
    355      1.40   thorpej 	 */
    356      1.45   thorpej 	if (auio.uio_resid > SSIZE_MAX) {
    357      1.45   thorpej 		error = EINVAL;
    358      1.45   thorpej 		goto out;
    359      1.45   thorpej 	}
    360      1.40   thorpej 
    361      1.38   thorpej 	cnt = auio.uio_resid;
    362      1.39   thorpej 	error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
    363      1.22  christos 	if (error) {
    364      1.15       cgd 		if (auio.uio_resid != cnt && (error == ERESTART ||
    365      1.15       cgd 		    error == EINTR || error == EWOULDBLOCK))
    366      1.15       cgd 			error = 0;
    367  1.83.2.3      yamt 		if (error == EPIPE) {
    368  1.83.2.3      yamt 			mutex_enter(&proclist_mutex);
    369  1.83.2.9      yamt 			psignal(curproc, SIGPIPE);
    370  1.83.2.3      yamt 			mutex_exit(&proclist_mutex);
    371  1.83.2.3      yamt 		}
    372      1.15       cgd 	}
    373      1.15       cgd 	cnt -= auio.uio_resid;
    374  1.83.2.4      yamt 	ktrgenio(fd, UIO_WRITE, buf, cnt, error);
    375      1.15       cgd 	*retval = cnt;
    376      1.45   thorpej  out:
    377  1.83.2.9      yamt 	fd_putfile(fd);
    378      1.15       cgd 	return (error);
    379      1.15       cgd }
    380      1.15       cgd 
    381      1.15       cgd /*
    382      1.15       cgd  * Gather write system call
    383      1.15       cgd  */
    384      1.22  christos int
    385  1.83.2.7      yamt sys_writev(struct lwp *l, const struct sys_writev_args *uap, register_t *retval)
    386      1.20   thorpej {
    387  1.83.2.7      yamt 	/* {
    388      1.53     lukem 		syscallarg(int)				fd;
    389      1.53     lukem 		syscallarg(const struct iovec *)	iovp;
    390      1.53     lukem 		syscallarg(int)				iovcnt;
    391  1.83.2.7      yamt 	} */
    392  1.83.2.4      yamt 
    393  1.83.2.5      yamt 	return do_filewritev(SCARG(uap, fd), SCARG(uap, iovp),
    394  1.83.2.4      yamt 	    SCARG(uap, iovcnt), NULL, FOF_UPDATE_OFFSET, retval);
    395  1.83.2.4      yamt }
    396  1.83.2.4      yamt 
    397  1.83.2.4      yamt int
    398  1.83.2.5      yamt do_filewritev(int fd, const struct iovec *iovp, int iovcnt,
    399  1.83.2.4      yamt     off_t *offset, int flags, register_t *retval)
    400  1.83.2.4      yamt {
    401  1.83.2.4      yamt 	struct uio	auio;
    402  1.83.2.4      yamt 	struct iovec	*iov, *needfree = NULL, aiov[UIO_SMALLIOV];
    403  1.83.2.4      yamt 	int		i, error;
    404  1.83.2.4      yamt 	size_t		cnt;
    405  1.83.2.4      yamt 	u_int		iovlen;
    406  1.83.2.4      yamt 	struct file	*fp;
    407  1.83.2.4      yamt 	struct iovec	*ktriov = NULL;
    408  1.83.2.4      yamt 
    409  1.83.2.4      yamt 	if (iovcnt == 0)
    410  1.83.2.4      yamt 		return EINVAL;
    411      1.39   thorpej 
    412  1.83.2.9      yamt 	if ((fp = fd_getfile(fd)) == NULL)
    413  1.83.2.4      yamt 		return EBADF;
    414      1.56   thorpej 
    415      1.70        pk 	if ((fp->f_flag & FWRITE) == 0) {
    416  1.83.2.9      yamt 		fd_putfile(fd);
    417  1.83.2.4      yamt 		return EBADF;
    418      1.70        pk 	}
    419      1.39   thorpej 
    420  1.83.2.4      yamt 	if (offset == NULL)
    421  1.83.2.4      yamt 		offset = &fp->f_offset;
    422  1.83.2.4      yamt 	else {
    423  1.83.2.4      yamt 		struct vnode *vp = fp->f_data;
    424  1.83.2.4      yamt 		if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
    425  1.83.2.4      yamt 			error = ESPIPE;
    426  1.83.2.4      yamt 			goto out;
    427  1.83.2.4      yamt 		}
    428  1.83.2.4      yamt 		/*
    429  1.83.2.4      yamt 		 * Test that the device is seekable ?
    430  1.83.2.4      yamt 		 * XXX This works because no file systems actually
    431  1.83.2.4      yamt 		 * XXX take any action on the seek operation.
    432  1.83.2.4      yamt 		 */
    433  1.83.2.4      yamt 		error = VOP_SEEK(vp, fp->f_offset, *offset, fp->f_cred);
    434  1.83.2.4      yamt 		if (error != 0)
    435  1.83.2.4      yamt 			goto out;
    436  1.83.2.4      yamt 	}
    437      1.15       cgd 
    438      1.42     perry 	iovlen = iovcnt * sizeof(struct iovec);
    439  1.83.2.4      yamt 	if (flags & FOF_IOV_SYSSPACE)
    440  1.83.2.4      yamt 		iov = __UNCONST(iovp);
    441  1.83.2.4      yamt 	else {
    442      1.15       cgd 		iov = aiov;
    443  1.83.2.4      yamt 		if ((u_int)iovcnt > UIO_SMALLIOV) {
    444  1.83.2.4      yamt 			if ((u_int)iovcnt > IOV_MAX) {
    445  1.83.2.4      yamt 				error = EINVAL;
    446  1.83.2.4      yamt 				goto out;
    447  1.83.2.4      yamt 			}
    448  1.83.2.4      yamt 			iov = kmem_alloc(iovlen, KM_SLEEP);
    449  1.83.2.4      yamt 			if (iov == NULL) {
    450  1.83.2.4      yamt 				error = ENOMEM;
    451  1.83.2.4      yamt 				goto out;
    452  1.83.2.4      yamt 			}
    453  1.83.2.4      yamt 			needfree = iov;
    454  1.83.2.4      yamt 		}
    455  1.83.2.4      yamt 		error = copyin(iovp, iov, iovlen);
    456  1.83.2.4      yamt 		if (error)
    457  1.83.2.4      yamt 			goto done;
    458      1.45   thorpej 	}
    459      1.41    kleink 
    460      1.15       cgd 	auio.uio_iov = iov;
    461      1.34   mycroft 	auio.uio_iovcnt = iovcnt;
    462      1.15       cgd 	auio.uio_rw = UIO_WRITE;
    463  1.83.2.5      yamt 	auio.uio_vmspace = curproc->p_vmspace;
    464  1.83.2.4      yamt 
    465      1.15       cgd 	auio.uio_resid = 0;
    466  1.83.2.4      yamt 	for (i = 0; i < iovcnt; i++, iov++) {
    467      1.15       cgd 		auio.uio_resid += iov->iov_len;
    468      1.40   thorpej 		/*
    469      1.40   thorpej 		 * Writes return ssize_t because -1 is returned on error.
    470      1.40   thorpej 		 * Therefore we must restrict the length to SSIZE_MAX to
    471      1.40   thorpej 		 * avoid garbage return values.
    472      1.40   thorpej 		 */
    473      1.40   thorpej 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
    474      1.15       cgd 			error = EINVAL;
    475      1.15       cgd 			goto done;
    476      1.15       cgd 		}
    477      1.15       cgd 	}
    478  1.83.2.4      yamt 
    479      1.15       cgd 	/*
    480      1.15       cgd 	 * if tracing, save a copy of iovec
    481      1.15       cgd 	 */
    482  1.83.2.4      yamt 	if (ktrpoint(KTR_GENIO))  {
    483  1.83.2.4      yamt 		ktriov = kmem_alloc(iovlen, KM_SLEEP);
    484  1.83.2.4      yamt 		if (ktriov != NULL)
    485  1.83.2.4      yamt 			memcpy(ktriov, auio.uio_iov, iovlen);
    486      1.15       cgd 	}
    487  1.83.2.4      yamt 
    488      1.15       cgd 	cnt = auio.uio_resid;
    489      1.39   thorpej 	error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
    490      1.22  christos 	if (error) {
    491      1.15       cgd 		if (auio.uio_resid != cnt && (error == ERESTART ||
    492      1.15       cgd 		    error == EINTR || error == EWOULDBLOCK))
    493      1.15       cgd 			error = 0;
    494  1.83.2.3      yamt 		if (error == EPIPE) {
    495  1.83.2.3      yamt 			mutex_enter(&proclist_mutex);
    496  1.83.2.9      yamt 			psignal(curproc, SIGPIPE);
    497  1.83.2.3      yamt 			mutex_exit(&proclist_mutex);
    498  1.83.2.3      yamt 		}
    499      1.15       cgd 	}
    500      1.15       cgd 	cnt -= auio.uio_resid;
    501  1.83.2.4      yamt 	*retval = cnt;
    502  1.83.2.4      yamt 
    503      1.78  drochner 	if (ktriov != NULL) {
    504  1.83.2.4      yamt 		ktrgeniov(fd, UIO_WRITE, ktriov, cnt, error);
    505  1.83.2.4      yamt 		kmem_free(ktriov, iovlen);
    506      1.15       cgd 	}
    507  1.83.2.4      yamt 
    508      1.45   thorpej  done:
    509      1.15       cgd 	if (needfree)
    510  1.83.2.4      yamt 		kmem_free(needfree, iovlen);
    511      1.45   thorpej  out:
    512  1.83.2.9      yamt 	fd_putfile(fd);
    513      1.15       cgd 	return (error);
    514      1.15       cgd }
    515      1.15       cgd 
    516      1.15       cgd /*
    517      1.15       cgd  * Ioctl system call
    518      1.15       cgd  */
    519      1.15       cgd /* ARGSUSED */
    520      1.22  christos int
    521  1.83.2.7      yamt sys_ioctl(struct lwp *l, const struct sys_ioctl_args *uap, register_t *retval)
    522      1.20   thorpej {
    523  1.83.2.7      yamt 	/* {
    524      1.53     lukem 		syscallarg(int)		fd;
    525      1.53     lukem 		syscallarg(u_long)	com;
    526  1.83.2.4      yamt 		syscallarg(void *)	data;
    527  1.83.2.7      yamt 	} */
    528      1.53     lukem 	struct file	*fp;
    529  1.83.2.4      yamt 	proc_t		*p;
    530      1.53     lukem 	struct filedesc	*fdp;
    531      1.53     lukem 	u_long		com;
    532      1.53     lukem 	int		error;
    533      1.53     lukem 	u_int		size;
    534  1.83.2.4      yamt 	void 		*data, *memp;
    535      1.53     lukem #define	STK_PARAMS	128
    536      1.53     lukem 	u_long		stkbuf[STK_PARAMS/sizeof(u_long)];
    537  1.83.2.9      yamt 	fdfile_t	*ff;
    538      1.15       cgd 
    539      1.53     lukem 	error = 0;
    540      1.69   thorpej 	p = l->l_proc;
    541      1.15       cgd 	fdp = p->p_fd;
    542      1.56   thorpej 
    543  1.83.2.9      yamt 	if ((fp = fd_getfile(SCARG(uap, fd))) == NULL)
    544      1.15       cgd 		return (EBADF);
    545      1.15       cgd 
    546      1.45   thorpej 	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
    547      1.45   thorpej 		error = EBADF;
    548      1.65       scw 		com = 0;
    549      1.45   thorpej 		goto out;
    550      1.45   thorpej 	}
    551      1.15       cgd 
    552  1.83.2.9      yamt 	ff = fdp->fd_ofiles[SCARG(uap, fd)];
    553      1.16       cgd 	switch (com = SCARG(uap, com)) {
    554      1.15       cgd 	case FIONCLEX:
    555  1.83.2.9      yamt 		ff->ff_exclose = 0;
    556      1.45   thorpej 		goto out;
    557      1.45   thorpej 
    558      1.15       cgd 	case FIOCLEX:
    559  1.83.2.9      yamt 		ff->ff_exclose = 1;
    560  1.83.2.9      yamt 		fdp->fd_exclose = 1;
    561      1.45   thorpej 		goto out;
    562      1.15       cgd 	}
    563      1.15       cgd 
    564      1.15       cgd 	/*
    565      1.15       cgd 	 * Interpret high order word to find amount of data to be
    566      1.15       cgd 	 * copied to/from the user's address space.
    567      1.15       cgd 	 */
    568      1.15       cgd 	size = IOCPARM_LEN(com);
    569      1.45   thorpej 	if (size > IOCPARM_MAX) {
    570      1.45   thorpej 		error = ENOTTY;
    571      1.45   thorpej 		goto out;
    572      1.45   thorpej 	}
    573      1.15       cgd 	memp = NULL;
    574      1.42     perry 	if (size > sizeof(stkbuf)) {
    575  1.83.2.4      yamt 		memp = kmem_alloc(size, KM_SLEEP);
    576      1.15       cgd 		data = memp;
    577      1.15       cgd 	} else
    578  1.83.2.4      yamt 		data = (void *)stkbuf;
    579      1.15       cgd 	if (com&IOC_IN) {
    580      1.15       cgd 		if (size) {
    581      1.31       cgd 			error = copyin(SCARG(uap, data), data, size);
    582      1.15       cgd 			if (error) {
    583      1.15       cgd 				if (memp)
    584  1.83.2.4      yamt 					kmem_free(memp, size);
    585      1.45   thorpej 				goto out;
    586      1.15       cgd 			}
    587  1.83.2.4      yamt 			ktrgenio(SCARG(uap, fd), UIO_WRITE, SCARG(uap, data),
    588  1.83.2.4      yamt 			    size, 0);
    589      1.15       cgd 		} else
    590  1.83.2.4      yamt 			*(void **)data = SCARG(uap, data);
    591      1.15       cgd 	} else if ((com&IOC_OUT) && size)
    592      1.15       cgd 		/*
    593      1.15       cgd 		 * Zero the buffer so the user always
    594      1.15       cgd 		 * gets back something deterministic.
    595      1.15       cgd 		 */
    596      1.44     perry 		memset(data, 0, size);
    597      1.15       cgd 	else if (com&IOC_VOID)
    598  1.83.2.4      yamt 		*(void **)data = SCARG(uap, data);
    599      1.15       cgd 
    600      1.15       cgd 	switch (com) {
    601      1.15       cgd 
    602      1.15       cgd 	case FIONBIO:
    603  1.83.2.7      yamt 		FILE_LOCK(fp);
    604      1.79  jdolecek 		if (*(int *)data != 0)
    605      1.15       cgd 			fp->f_flag |= FNONBLOCK;
    606      1.15       cgd 		else
    607      1.15       cgd 			fp->f_flag &= ~FNONBLOCK;
    608  1.83.2.7      yamt 		FILE_UNLOCK(fp);
    609  1.83.2.9      yamt 		error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, data);
    610      1.15       cgd 		break;
    611      1.15       cgd 
    612      1.15       cgd 	case FIOASYNC:
    613  1.83.2.7      yamt 		FILE_LOCK(fp);
    614      1.79  jdolecek 		if (*(int *)data != 0)
    615      1.15       cgd 			fp->f_flag |= FASYNC;
    616      1.15       cgd 		else
    617      1.15       cgd 			fp->f_flag &= ~FASYNC;
    618  1.83.2.7      yamt 		FILE_UNLOCK(fp);
    619  1.83.2.9      yamt 		error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, data);
    620      1.15       cgd 		break;
    621      1.15       cgd 
    622      1.15       cgd 	default:
    623  1.83.2.9      yamt 		error = (*fp->f_ops->fo_ioctl)(fp, com, data);
    624      1.15       cgd 		/*
    625      1.15       cgd 		 * Copy any data to user, size was
    626      1.15       cgd 		 * already set and checked above.
    627      1.15       cgd 		 */
    628      1.73       dsl 		if (error == 0 && (com&IOC_OUT) && size) {
    629      1.31       cgd 			error = copyout(data, SCARG(uap, data), size);
    630  1.83.2.4      yamt 			ktrgenio(SCARG(uap, fd), UIO_READ, SCARG(uap, data),
    631  1.83.2.4      yamt 			    size, error);
    632      1.73       dsl 		}
    633      1.15       cgd 		break;
    634      1.15       cgd 	}
    635      1.15       cgd 	if (memp)
    636  1.83.2.4      yamt 		kmem_free(memp, size);
    637      1.45   thorpej  out:
    638  1.83.2.9      yamt 	fd_putfile(SCARG(uap, fd));
    639      1.61    atatat 	switch (error) {
    640      1.61    atatat 	case -1:
    641      1.61    atatat 		printf("sys_ioctl: _IO%s%s('%c', %lu, %lu) returned -1: "
    642      1.61    atatat 		    "pid=%d comm=%s\n",
    643      1.61    atatat 		    (com & IOC_IN) ? "W" : "", (com & IOC_OUT) ? "R" : "",
    644      1.61    atatat 		    (char)IOCGROUP(com), (com & 0xff), IOCPARM_LEN(com),
    645      1.61    atatat 		    p->p_pid, p->p_comm);
    646      1.61    atatat 		/* FALLTHROUGH */
    647      1.61    atatat 	case EPASSTHROUGH:
    648      1.61    atatat 		error = ENOTTY;
    649      1.61    atatat 		/* FALLTHROUGH */
    650      1.61    atatat 	default:
    651      1.61    atatat 		return (error);
    652      1.61    atatat 	}
    653      1.15       cgd }
    654