The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/sys_generic.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d3b7c384b8e1d15cac4760f10113c8f4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.