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/compat/linux/linux_file.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 /*-
    2  * Copyright (c) 1994-1995 Søren Schmidt
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer
   10  *    in this position and unchanged.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * $FreeBSD: releng/5.1/sys/compat/linux/linux_file.c 113917 2003-04-23 18:13:26Z jhb $
   29  */
   30 
   31 #include "opt_compat.h"
   32 #include "opt_mac.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/conf.h>
   37 #include <sys/dirent.h>
   38 #include <sys/fcntl.h>
   39 #include <sys/file.h>
   40 #include <sys/filedesc.h>
   41 #include <sys/lock.h>
   42 #include <sys/mac.h>
   43 #include <sys/malloc.h>
   44 #include <sys/mount.h>
   45 #include <sys/mutex.h>
   46 #include <sys/proc.h>
   47 #include <sys/syscallsubr.h>
   48 #include <sys/sysproto.h>
   49 #include <sys/tty.h>
   50 #include <sys/vnode.h>
   51 
   52 #include <ufs/ufs/extattr.h>
   53 #include <ufs/ufs/quota.h>
   54 #include <ufs/ufs/ufsmount.h>
   55 
   56 #include <machine/../linux/linux.h>
   57 #include <machine/../linux/linux_proto.h>
   58 #include <compat/linux/linux_util.h>
   59 
   60 #ifndef __alpha__
   61 int
   62 linux_creat(struct thread *td, struct linux_creat_args *args)
   63 {
   64     char *path;
   65     int error;
   66 
   67     LCONVPATHEXIST(td, args->path, &path);
   68 
   69 #ifdef DEBUG
   70         if (ldebug(creat))
   71                 printf(ARGS(creat, "%s, %d"), path, args->mode);
   72 #endif
   73     error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
   74         args->mode);
   75     LFREEPATH(path);
   76     return (error);
   77 }
   78 #endif /*!__alpha__*/
   79 
   80 int
   81 linux_open(struct thread *td, struct linux_open_args *args)
   82 {
   83     struct proc *p = td->td_proc;
   84     char *path;
   85     int bsd_flags, error;
   86 
   87     if (args->flags & LINUX_O_CREAT)
   88         LCONVPATHCREAT(td, args->path, &path);
   89     else
   90         LCONVPATHEXIST(td, args->path, &path);
   91 
   92 #ifdef DEBUG
   93         if (ldebug(open))
   94                 printf(ARGS(open, "%s, 0x%x, 0x%x"),
   95                     path, args->flags, args->mode);
   96 #endif
   97     bsd_flags = 0;
   98     if (args->flags & LINUX_O_RDONLY)
   99         bsd_flags |= O_RDONLY;
  100     if (args->flags & LINUX_O_WRONLY)
  101         bsd_flags |= O_WRONLY;
  102     if (args->flags & LINUX_O_RDWR)
  103         bsd_flags |= O_RDWR;
  104     if (args->flags & LINUX_O_NDELAY)
  105         bsd_flags |= O_NONBLOCK;
  106     if (args->flags & LINUX_O_APPEND)
  107         bsd_flags |= O_APPEND;
  108     if (args->flags & LINUX_O_SYNC)
  109         bsd_flags |= O_FSYNC;
  110     if (args->flags & LINUX_O_NONBLOCK)
  111         bsd_flags |= O_NONBLOCK;
  112     if (args->flags & LINUX_FASYNC)
  113         bsd_flags |= O_ASYNC;
  114     if (args->flags & LINUX_O_CREAT)
  115         bsd_flags |= O_CREAT;
  116     if (args->flags & LINUX_O_TRUNC)
  117         bsd_flags |= O_TRUNC;
  118     if (args->flags & LINUX_O_EXCL)
  119         bsd_flags |= O_EXCL;
  120     if (args->flags & LINUX_O_NOCTTY)
  121         bsd_flags |= O_NOCTTY;
  122 
  123     error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode);
  124     PROC_LOCK(p);
  125     if (!error && !(bsd_flags & O_NOCTTY) &&
  126         SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
  127         struct file *fp;
  128 
  129         PROC_UNLOCK(p);
  130         error = fget(td, td->td_retval[0], &fp);
  131         if (!error) {
  132                 if (fp->f_type == DTYPE_VNODE)
  133                         fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred,
  134                             td);
  135             fdrop(fp, td);
  136         }
  137     } else {
  138         PROC_UNLOCK(p);
  139 #ifdef DEBUG
  140         if (ldebug(open))
  141                 printf(LMSG("open returns error %d"), error);
  142 #endif
  143     }
  144     LFREEPATH(path);
  145     return error;
  146 }
  147 
  148 int
  149 linux_lseek(struct thread *td, struct linux_lseek_args *args)
  150 {
  151 
  152     struct lseek_args /* {
  153         int fd;
  154         int pad;
  155         off_t offset;
  156         int whence;
  157     } */ tmp_args;
  158     int error;
  159 
  160 #ifdef DEBUG
  161         if (ldebug(lseek))
  162                 printf(ARGS(lseek, "%d, %ld, %d"),
  163                     args->fdes, (long)args->off, args->whence);
  164 #endif
  165     tmp_args.fd = args->fdes;
  166     tmp_args.offset = (off_t)args->off;
  167     tmp_args.whence = args->whence;
  168     error = lseek(td, &tmp_args);
  169     return error;
  170 }
  171 
  172 #ifndef __alpha__
  173 int
  174 linux_llseek(struct thread *td, struct linux_llseek_args *args)
  175 {
  176         struct lseek_args bsd_args;
  177         int error;
  178         off_t off;
  179 
  180 #ifdef DEBUG
  181         if (ldebug(llseek))
  182                 printf(ARGS(llseek, "%d, %d:%d, %d"),
  183                     args->fd, args->ohigh, args->olow, args->whence);
  184 #endif
  185         off = (args->olow) | (((off_t) args->ohigh) << 32);
  186 
  187         bsd_args.fd = args->fd;
  188         bsd_args.offset = off;
  189         bsd_args.whence = args->whence;
  190 
  191         if ((error = lseek(td, &bsd_args)))
  192                 return error;
  193 
  194         if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
  195                 return error;
  196 
  197         td->td_retval[0] = 0;
  198         return 0;
  199 }
  200 #endif /*!__alpha__*/
  201 
  202 #ifndef __alpha__
  203 int
  204 linux_readdir(struct thread *td, struct linux_readdir_args *args)
  205 {
  206         struct linux_getdents_args lda;
  207 
  208         lda.fd = args->fd;
  209         lda.dent = args->dent;
  210         lda.count = 1;
  211         return linux_getdents(td, &lda);
  212 }
  213 #endif /*!__alpha__*/
  214 
  215 /*
  216  * Note that linux_getdents(2) and linux_getdents64(2) have the same
  217  * arguments. They only differ in the definition of struct dirent they
  218  * operate on. We use this to common the code, with the exception of
  219  * accessing struct dirent. Note that linux_readdir(2) is implemented
  220  * by means of linux_getdents(2). In this case we never operate on
  221  * struct dirent64 and thus don't need to handle it...
  222  */
  223 
  224 struct l_dirent {
  225         l_long          d_ino;
  226         l_off_t         d_off;
  227         l_ushort        d_reclen;
  228         char            d_name[LINUX_NAME_MAX + 1];
  229 };
  230 
  231 struct l_dirent64 {
  232         uint64_t        d_ino;
  233         int64_t         d_off;
  234         l_ushort        d_reclen;
  235         u_char          d_type;
  236         char            d_name[LINUX_NAME_MAX + 1];
  237 };
  238 
  239 #define LINUX_RECLEN(de,namlen) \
  240     ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
  241 
  242 #define LINUX_DIRBLKSIZ         512
  243 
  244 static int
  245 getdents_common(struct thread *td, struct linux_getdents64_args *args,
  246     int is64bit)
  247 {
  248         struct dirent *bdp;
  249         struct vnode *vp;
  250         caddr_t inp, buf;               /* BSD-format */
  251         int len, reclen;                /* BSD-format */
  252         caddr_t outp;                   /* Linux-format */
  253         int resid, linuxreclen=0;       /* Linux-format */
  254         struct file *fp;
  255         struct uio auio;
  256         struct iovec aiov;
  257         struct vattr va;
  258         off_t off;
  259         struct l_dirent linux_dirent;
  260         struct l_dirent64 linux_dirent64;
  261         int buflen, error, eofflag, nbytes, justone;
  262         u_long *cookies = NULL, *cookiep;
  263         int ncookies;
  264 
  265         if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0)
  266                 return (error);
  267 
  268         if ((fp->f_flag & FREAD) == 0) {
  269                 fdrop(fp, td);
  270                 return (EBADF);
  271         }
  272 
  273         vp = fp->f_data;
  274         if (vp->v_type != VDIR) {
  275                 fdrop(fp, td);
  276                 return (EINVAL);
  277         }
  278 
  279         if ((error = VOP_GETATTR(vp, &va, td->td_ucred, td))) {
  280                 fdrop(fp, td);
  281                 return (error);
  282         }
  283 
  284         nbytes = args->count;
  285         if (nbytes == 1) {
  286                 /* readdir(2) case. Always struct dirent. */
  287                 if (is64bit) {
  288                         fdrop(fp, td);
  289                         return (EINVAL);
  290                 }
  291                 nbytes = sizeof(linux_dirent);
  292                 justone = 1;
  293         } else
  294                 justone = 0;
  295 
  296         off = fp->f_offset;
  297 
  298         buflen = max(LINUX_DIRBLKSIZ, nbytes);
  299         buflen = min(buflen, MAXBSIZE);
  300         buf = malloc(buflen, M_TEMP, M_WAITOK);
  301         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  302 
  303 again:
  304         aiov.iov_base = buf;
  305         aiov.iov_len = buflen;
  306         auio.uio_iov = &aiov;
  307         auio.uio_iovcnt = 1;
  308         auio.uio_rw = UIO_READ;
  309         auio.uio_segflg = UIO_SYSSPACE;
  310         auio.uio_td = td;
  311         auio.uio_resid = buflen;
  312         auio.uio_offset = off;
  313 
  314         if (cookies) {
  315                 free(cookies, M_TEMP);
  316                 cookies = NULL;
  317         }
  318 
  319 #ifdef MAC
  320         /*
  321          * Do directory search MAC check using non-cached credentials.
  322          */
  323         if ((error = mac_check_vnode_readdir(td->td_ucred, vp)))
  324                 goto out;
  325 #endif /* MAC */
  326         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
  327                  &cookies)))
  328                 goto out;
  329 
  330         inp = buf;
  331         outp = (caddr_t)args->dirent;
  332         resid = nbytes;
  333         if ((len = buflen - auio.uio_resid) <= 0)
  334                 goto eof;
  335 
  336         cookiep = cookies;
  337 
  338         if (cookies) {
  339                 /*
  340                  * When using cookies, the vfs has the option of reading from
  341                  * a different offset than that supplied (UFS truncates the
  342                  * offset to a block boundary to make sure that it never reads
  343                  * partway through a directory entry, even if the directory
  344                  * has been compacted).
  345                  */
  346                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
  347                         bdp = (struct dirent *) inp;
  348                         len -= bdp->d_reclen;
  349                         inp += bdp->d_reclen;
  350                         cookiep++;
  351                         ncookies--;
  352                 }
  353         }
  354 
  355         while (len > 0) {
  356                 if (cookiep && ncookies == 0)
  357                         break;
  358                 bdp = (struct dirent *) inp;
  359                 reclen = bdp->d_reclen;
  360                 if (reclen & 3) {
  361                         error = EFAULT;
  362                         goto out;
  363                 }
  364 
  365                 if (bdp->d_fileno == 0) {
  366                         inp += reclen;
  367                         if (cookiep) {
  368                                 off = *cookiep++;
  369                                 ncookies--;
  370                         } else
  371                                 off += reclen;
  372 
  373                         len -= reclen;
  374                         continue;
  375                 }
  376 
  377                 linuxreclen = (is64bit)
  378                     ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
  379                     : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
  380 
  381                 if (reclen > len || resid < linuxreclen) {
  382                         outp++;
  383                         break;
  384                 }
  385 
  386                 if (justone) {
  387                         /* readdir(2) case. */
  388                         linux_dirent.d_ino = (l_long)bdp->d_fileno;
  389                         linux_dirent.d_off = (l_off_t)linuxreclen;
  390                         linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
  391                         strcpy(linux_dirent.d_name, bdp->d_name);
  392                         error = copyout(&linux_dirent, outp, linuxreclen);
  393                 } else {
  394                         if (is64bit) {
  395                                 linux_dirent64.d_ino = bdp->d_fileno;
  396                                 linux_dirent64.d_off = (cookiep)
  397                                     ? (l_off_t)*cookiep
  398                                     : (l_off_t)(off + reclen);
  399                                 linux_dirent64.d_reclen =
  400                                     (l_ushort)linuxreclen;
  401                                 linux_dirent64.d_type = bdp->d_type;
  402                                 strcpy(linux_dirent64.d_name, bdp->d_name);
  403                                 error = copyout(&linux_dirent64, outp,
  404                                     linuxreclen);
  405                         } else {
  406                                 linux_dirent.d_ino = bdp->d_fileno;
  407                                 linux_dirent.d_off = (cookiep)
  408                                     ? (l_off_t)*cookiep
  409                                     : (l_off_t)(off + reclen);
  410                                 linux_dirent.d_reclen = (l_ushort)linuxreclen;
  411                                 strcpy(linux_dirent.d_name, bdp->d_name);
  412                                 error = copyout(&linux_dirent, outp,
  413                                     linuxreclen);
  414                         }
  415                 }
  416                 if (error)
  417                         goto out;
  418 
  419                 inp += reclen;
  420                 if (cookiep) {
  421                         off = *cookiep++;
  422                         ncookies--;
  423                 } else
  424                         off += reclen;
  425 
  426                 outp += linuxreclen;
  427                 resid -= linuxreclen;
  428                 len -= reclen;
  429                 if (justone)
  430                         break;
  431         }
  432 
  433         if (outp == (caddr_t)args->dirent)
  434                 goto again;
  435 
  436         fp->f_offset = off;
  437         if (justone)
  438                 nbytes = resid + linuxreclen;
  439 
  440 eof:
  441         td->td_retval[0] = nbytes - resid;
  442 
  443 out:
  444         if (cookies)
  445                 free(cookies, M_TEMP);
  446 
  447         VOP_UNLOCK(vp, 0, td);
  448         fdrop(fp, td);
  449         free(buf, M_TEMP);
  450         return (error);
  451 }
  452 
  453 int
  454 linux_getdents(struct thread *td, struct linux_getdents_args *args)
  455 {
  456 
  457 #ifdef DEBUG
  458         if (ldebug(getdents))
  459                 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
  460 #endif
  461 
  462         return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
  463 }
  464 
  465 int
  466 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
  467 {
  468 
  469 #ifdef DEBUG
  470         if (ldebug(getdents64))
  471                 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
  472 #endif
  473 
  474         return (getdents_common(td, args, 1));
  475 }
  476 
  477 /*
  478  * These exist mainly for hooks for doing /compat/linux translation.
  479  */
  480 
  481 int
  482 linux_access(struct thread *td, struct linux_access_args *args)
  483 {
  484         char *path;
  485         int error;
  486 
  487         LCONVPATHEXIST(td, args->path, &path);
  488 
  489 #ifdef DEBUG
  490         if (ldebug(access))
  491                 printf(ARGS(access, "%s, %d"), path, args->flags);
  492 #endif
  493         error = kern_access(td, path, UIO_SYSSPACE, args->flags);
  494         LFREEPATH(path);
  495         return (error);
  496 }
  497 
  498 int
  499 linux_unlink(struct thread *td, struct linux_unlink_args *args)
  500 {
  501         char *path;
  502         int error;
  503 
  504         LCONVPATHEXIST(td, args->path, &path);
  505 
  506 #ifdef DEBUG
  507         if (ldebug(unlink))
  508                 printf(ARGS(unlink, "%s"), path);
  509 #endif
  510 
  511         error = kern_unlink(td, path, UIO_SYSSPACE);
  512         LFREEPATH(path);
  513         return (error);
  514 }
  515 
  516 int
  517 linux_chdir(struct thread *td, struct linux_chdir_args *args)
  518 {
  519         char *path;
  520         int error;
  521 
  522         LCONVPATHEXIST(td, args->path, &path);
  523 
  524 #ifdef DEBUG
  525         if (ldebug(chdir))
  526                 printf(ARGS(chdir, "%s"), path);
  527 #endif
  528         error = kern_chdir(td, path, UIO_SYSSPACE);
  529         LFREEPATH(path);
  530         return (error);
  531 }
  532 
  533 int
  534 linux_chmod(struct thread *td, struct linux_chmod_args *args)
  535 {
  536         char *path;
  537         int error;
  538 
  539         LCONVPATHEXIST(td, args->path, &path);
  540 
  541 #ifdef DEBUG
  542         if (ldebug(chmod))
  543                 printf(ARGS(chmod, "%s, %d"), path, args->mode);
  544 #endif
  545         error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
  546         LFREEPATH(path);
  547         return (error);
  548 }
  549 
  550 int
  551 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
  552 {
  553         char *path;
  554         int error;
  555 
  556         LCONVPATHCREAT(td, args->path, &path);
  557 
  558 #ifdef DEBUG
  559         if (ldebug(mkdir))
  560                 printf(ARGS(mkdir, "%s, %d"), path, args->mode);
  561 #endif
  562         error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
  563         LFREEPATH(path);
  564         return (error);
  565 }
  566 
  567 int
  568 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
  569 {
  570         char *path;
  571         int error;
  572 
  573         LCONVPATHEXIST(td, args->path, &path);
  574 
  575 #ifdef DEBUG
  576         if (ldebug(rmdir))
  577                 printf(ARGS(rmdir, "%s"), path);
  578 #endif
  579         error = kern_rmdir(td, path, UIO_SYSSPACE);
  580         LFREEPATH(path);
  581         return (error);
  582 }
  583 
  584 int
  585 linux_rename(struct thread *td, struct linux_rename_args *args)
  586 {
  587         char *from, *to;
  588         int error;
  589 
  590         LCONVPATHEXIST(td, args->from, &from);
  591         /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
  592         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
  593         if (to == NULL) {
  594                 LFREEPATH(from);
  595                 return (error);
  596         }
  597 
  598 #ifdef DEBUG
  599         if (ldebug(rename))
  600                 printf(ARGS(rename, "%s, %s"), from, to);
  601 #endif
  602         error = kern_rename(td, from, to, UIO_SYSSPACE);
  603         LFREEPATH(from);
  604         LFREEPATH(to);
  605         return (error);
  606 }
  607 
  608 int
  609 linux_symlink(struct thread *td, struct linux_symlink_args *args)
  610 {
  611         char *path, *to;
  612         int error;
  613 
  614         LCONVPATHEXIST(td, args->path, &path);
  615         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
  616         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
  617         if (to == NULL) {
  618                 LFREEPATH(path);
  619                 return (error);
  620         }
  621 
  622 #ifdef DEBUG
  623         if (ldebug(symlink))
  624                 printf(ARGS(symlink, "%s, %s"), path, to);
  625 #endif
  626         error = kern_symlink(td, path, to, UIO_SYSSPACE);
  627         LFREEPATH(path);
  628         LFREEPATH(to);
  629         return (error);
  630 }
  631 
  632 int
  633 linux_readlink(struct thread *td, struct linux_readlink_args *args)
  634 {
  635         char *name;
  636         int error;
  637 
  638         LCONVPATHEXIST(td, args->name, &name);
  639 
  640 #ifdef DEBUG
  641         if (ldebug(readlink))
  642                 printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
  643                     args->count);
  644 #endif
  645         error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
  646             args->count);
  647         LFREEPATH(name);
  648         return (error);
  649 }
  650 
  651 int
  652 linux_truncate(struct thread *td, struct linux_truncate_args *args)
  653 {
  654         char *path;
  655         int error;
  656 
  657         LCONVPATHEXIST(td, args->path, &path);
  658 
  659 #ifdef DEBUG
  660         if (ldebug(truncate))
  661                 printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
  662 #endif
  663 
  664         error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
  665         LFREEPATH(path);
  666         return (error);
  667 }
  668 
  669 int
  670 linux_link(struct thread *td, struct linux_link_args *args)
  671 {
  672         char *path, *to;
  673         int error;
  674 
  675         LCONVPATHEXIST(td, args->path, &path);
  676         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
  677         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
  678         if (to == NULL) {
  679                 LFREEPATH(path);
  680                 return (error);
  681         }
  682 
  683 #ifdef DEBUG
  684         if (ldebug(link))
  685                 printf(ARGS(link, "%s, %s"), path, to);
  686 #endif
  687         error = kern_link(td, path, to, UIO_SYSSPACE);
  688         LFREEPATH(path);
  689         LFREEPATH(to);
  690         return (error);
  691 }
  692 
  693 #ifndef __alpha__
  694 int
  695 linux_fdatasync(td, uap)
  696         struct thread *td;
  697         struct linux_fdatasync_args *uap;
  698 {
  699         struct fsync_args bsd;
  700 
  701         bsd.fd = uap->fd;
  702         return fsync(td, &bsd);
  703 }
  704 #endif /*!__alpha__*/
  705 
  706 int
  707 linux_pread(td, uap)
  708         struct thread *td;
  709         struct linux_pread_args *uap;
  710 {
  711         struct pread_args bsd;
  712 
  713         bsd.fd = uap->fd;
  714         bsd.buf = uap->buf;
  715         bsd.nbyte = uap->nbyte;
  716         bsd.offset = uap->offset;
  717         return pread(td, &bsd);
  718 }
  719 
  720 int
  721 linux_pwrite(td, uap)
  722         struct thread *td;
  723         struct linux_pwrite_args *uap;
  724 {
  725         struct pwrite_args bsd;
  726 
  727         bsd.fd = uap->fd;
  728         bsd.buf = uap->buf;
  729         bsd.nbyte = uap->nbyte;
  730         bsd.offset = uap->offset;
  731         return pwrite(td, &bsd);
  732 }
  733 
  734 int
  735 linux_mount(struct thread *td, struct linux_mount_args *args)
  736 {
  737         struct ufs_args ufs;
  738         char fstypename[MFSNAMELEN];
  739         char mntonname[MNAMELEN], mntfromname[MNAMELEN];
  740         int error;
  741         int fsflags;
  742         const char *fstype;
  743         void *fsdata;
  744 
  745         error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
  746             NULL);
  747         if (error)
  748                 return (error);
  749         error = copyinstr(args->specialfile, mntfromname, MFSNAMELEN - 1, NULL);
  750         if (error)
  751                 return (error);
  752         error = copyinstr(args->dir, mntonname, MFSNAMELEN - 1, NULL);
  753         if (error)
  754                 return (error);
  755 
  756 #ifdef DEBUG
  757         if (ldebug(mount))
  758                 printf(ARGS(mount, "%s, %s, %s"),
  759                     fstypename, mntfromname, mntonname);
  760 #endif
  761 
  762         if (strcmp(fstypename, "ext2") == 0) {
  763                 fstype = "ext2fs";
  764                 fsdata = &ufs;
  765                 ufs.fspec = mntfromname;
  766 #define DEFAULT_ROOTID          -2
  767                 ufs.export.ex_root = DEFAULT_ROOTID;
  768                 ufs.export.ex_flags =
  769                     args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
  770         } else if (strcmp(fstypename, "proc") == 0) {
  771                 fstype = "linprocfs";
  772                 fsdata = NULL;
  773         } else {
  774                 return (ENODEV);
  775         }
  776 
  777         fsflags = 0;
  778 
  779         if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
  780                 /*
  781                  * Linux SYNC flag is not included; the closest equivalent
  782                  * FreeBSD has is !ASYNC, which is our default.
  783                  */
  784                 if (args->rwflag & LINUX_MS_RDONLY)
  785                         fsflags |= MNT_RDONLY;
  786                 if (args->rwflag & LINUX_MS_NOSUID)
  787                         fsflags |= MNT_NOSUID;
  788                 if (args->rwflag & LINUX_MS_NODEV)
  789                         fsflags |= MNT_NODEV;
  790                 if (args->rwflag & LINUX_MS_NOEXEC)
  791                         fsflags |= MNT_NOEXEC;
  792                 if (args->rwflag & LINUX_MS_REMOUNT)
  793                         fsflags |= MNT_UPDATE;
  794         }
  795 
  796         return (vfs_mount(td, fstype, mntonname, fsflags, fsdata));
  797 }
  798 
  799 int
  800 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
  801 {
  802         struct linux_umount_args args2;
  803 
  804         args2.path = args->path;
  805         args2.flags = 0;
  806         return (linux_umount(td, &args2));
  807 }
  808 
  809 int
  810 linux_umount(struct thread *td, struct linux_umount_args *args)
  811 {
  812         struct unmount_args bsd;
  813 
  814         bsd.path = args->path;
  815         bsd.flags = args->flags;        /* XXX correct? */
  816         return (unmount(td, &bsd));
  817 }
  818 
  819 /*
  820  * fcntl family of syscalls
  821  */
  822 
  823 struct l_flock {
  824         l_short         l_type;
  825         l_short         l_whence;
  826         l_off_t         l_start;
  827         l_off_t         l_len;
  828         l_pid_t         l_pid;
  829 };
  830 
  831 static void
  832 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
  833 {
  834         switch (linux_flock->l_type) {
  835         case LINUX_F_RDLCK:
  836                 bsd_flock->l_type = F_RDLCK;
  837                 break;
  838         case LINUX_F_WRLCK:
  839                 bsd_flock->l_type = F_WRLCK;
  840                 break;
  841         case LINUX_F_UNLCK:
  842                 bsd_flock->l_type = F_UNLCK;
  843                 break;
  844         default:
  845                 bsd_flock->l_type = -1;
  846                 break;
  847         }
  848         bsd_flock->l_whence = linux_flock->l_whence;
  849         bsd_flock->l_start = (off_t)linux_flock->l_start;
  850         bsd_flock->l_len = (off_t)linux_flock->l_len;
  851         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
  852 }
  853 
  854 static void
  855 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
  856 {
  857         switch (bsd_flock->l_type) {
  858         case F_RDLCK:
  859                 linux_flock->l_type = LINUX_F_RDLCK;
  860                 break;
  861         case F_WRLCK:
  862                 linux_flock->l_type = LINUX_F_WRLCK;
  863                 break;
  864         case F_UNLCK:
  865                 linux_flock->l_type = LINUX_F_UNLCK;
  866                 break;
  867         }
  868         linux_flock->l_whence = bsd_flock->l_whence;
  869         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
  870         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
  871         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
  872 }
  873 
  874 #if defined(__i386__)
  875 struct l_flock64 {
  876         l_short         l_type;
  877         l_short         l_whence;
  878         l_loff_t        l_start;
  879         l_loff_t        l_len;
  880         l_pid_t         l_pid;
  881 };
  882 
  883 static void
  884 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
  885 {
  886         switch (linux_flock->l_type) {
  887         case LINUX_F_RDLCK:
  888                 bsd_flock->l_type = F_RDLCK;
  889                 break;
  890         case LINUX_F_WRLCK:
  891                 bsd_flock->l_type = F_WRLCK;
  892                 break;
  893         case LINUX_F_UNLCK:
  894                 bsd_flock->l_type = F_UNLCK;
  895                 break;
  896         default:
  897                 bsd_flock->l_type = -1;
  898                 break;
  899         }
  900         bsd_flock->l_whence = linux_flock->l_whence;
  901         bsd_flock->l_start = (off_t)linux_flock->l_start;
  902         bsd_flock->l_len = (off_t)linux_flock->l_len;
  903         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
  904 }
  905 
  906 static void
  907 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
  908 {
  909         switch (bsd_flock->l_type) {
  910         case F_RDLCK:
  911                 linux_flock->l_type = LINUX_F_RDLCK;
  912                 break;
  913         case F_WRLCK:
  914                 linux_flock->l_type = LINUX_F_WRLCK;
  915                 break;
  916         case F_UNLCK:
  917                 linux_flock->l_type = LINUX_F_UNLCK;
  918                 break;
  919         }
  920         linux_flock->l_whence = bsd_flock->l_whence;
  921         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
  922         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
  923         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
  924 }
  925 #endif /* __i386__ */
  926 
  927 #if defined(__alpha__)
  928 #define linux_fcntl64_args      linux_fcntl_args
  929 #endif
  930 
  931 static int
  932 fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
  933 {
  934         struct l_flock linux_flock;
  935         struct flock bsd_flock;
  936         struct file *fp;
  937         long arg;
  938         int error, result;
  939 
  940         switch (args->cmd) {
  941         case LINUX_F_DUPFD:
  942                 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
  943 
  944         case LINUX_F_GETFD:
  945                 return (kern_fcntl(td, args->fd, F_GETFD, 0));
  946 
  947         case LINUX_F_SETFD:
  948                 return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
  949 
  950         case LINUX_F_GETFL:
  951                 error = kern_fcntl(td, args->fd, F_GETFL, 0);
  952                 result = td->td_retval[0];
  953                 td->td_retval[0] = 0;
  954                 if (result & O_RDONLY)
  955                         td->td_retval[0] |= LINUX_O_RDONLY;
  956                 if (result & O_WRONLY)
  957                         td->td_retval[0] |= LINUX_O_WRONLY;
  958                 if (result & O_RDWR)
  959                         td->td_retval[0] |= LINUX_O_RDWR;
  960                 if (result & O_NDELAY)
  961                         td->td_retval[0] |= LINUX_O_NONBLOCK;
  962                 if (result & O_APPEND)
  963                         td->td_retval[0] |= LINUX_O_APPEND;
  964                 if (result & O_FSYNC)
  965                         td->td_retval[0] |= LINUX_O_SYNC;
  966                 if (result & O_ASYNC)
  967                         td->td_retval[0] |= LINUX_FASYNC;
  968                 return (error);
  969 
  970         case LINUX_F_SETFL:
  971                 arg = 0;
  972                 if (args->arg & LINUX_O_NDELAY)
  973                         arg |= O_NONBLOCK;
  974                 if (args->arg & LINUX_O_APPEND)
  975                         arg |= O_APPEND;
  976                 if (args->arg & LINUX_O_SYNC)
  977                         arg |= O_FSYNC;
  978                 if (args->arg & LINUX_FASYNC)
  979                         arg |= O_ASYNC;
  980                 return (kern_fcntl(td, args->fd, F_SETFL, arg));
  981 
  982         case LINUX_F_GETLK:
  983                 error = copyin((void *)args->arg, &linux_flock,
  984                     sizeof(linux_flock));
  985                 if (error)
  986                         return (error);
  987                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
  988                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
  989                 if (error)
  990                         return (error);
  991                 bsd_to_linux_flock(&bsd_flock, &linux_flock);
  992                 return (copyout(&linux_flock, (void *)args->arg,
  993                     sizeof(linux_flock)));
  994 
  995         case LINUX_F_SETLK:
  996                 error = copyin((void *)args->arg, &linux_flock,
  997                     sizeof(linux_flock));
  998                 if (error)
  999                         return (error);
 1000                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
 1001                 return (kern_fcntl(td, args->fd, F_SETLK,
 1002                     (intptr_t)&bsd_flock));
 1003 
 1004         case LINUX_F_SETLKW:
 1005                 error = copyin((void *)args->arg, &linux_flock,
 1006                     sizeof(linux_flock));
 1007                 if (error)
 1008                         return (error);
 1009                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
 1010                 return (kern_fcntl(td, args->fd, F_SETLKW,
 1011                      (intptr_t)&bsd_flock));
 1012 
 1013         case LINUX_F_GETOWN:
 1014                 return (kern_fcntl(td, args->fd, F_GETOWN, 0));
 1015 
 1016         case LINUX_F_SETOWN:
 1017                 /*
 1018                  * XXX some Linux applications depend on F_SETOWN having no
 1019                  * significant effect for pipes (SIGIO is not delivered for
 1020                  * pipes under Linux-2.2.35 at least).
 1021                  */
 1022                 error = fget(td, args->fd, &fp);
 1023                 if (error)
 1024                         return (error);
 1025                 if (fp->f_type == DTYPE_PIPE) {
 1026                         fdrop(fp, td);
 1027                         return (EINVAL);
 1028                 }
 1029                 fdrop(fp, td);
 1030 
 1031                 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
 1032         }
 1033 
 1034         return (EINVAL);
 1035 }
 1036 
 1037 int
 1038 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
 1039 {
 1040         struct linux_fcntl64_args args64;
 1041 
 1042 #ifdef DEBUG
 1043         if (ldebug(fcntl))
 1044                 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
 1045 #endif
 1046 
 1047         args64.fd = args->fd;
 1048         args64.cmd = args->cmd;
 1049         args64.arg = args->arg;
 1050         return (fcntl_common(td, &args64));
 1051 }
 1052 
 1053 #if defined(__i386__)
 1054 int
 1055 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
 1056 {
 1057         struct l_flock64 linux_flock;
 1058         struct flock bsd_flock;
 1059         int error;
 1060 
 1061 #ifdef DEBUG
 1062         if (ldebug(fcntl64))
 1063                 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
 1064 #endif
 1065 
 1066         switch (args->cmd) {
 1067         case LINUX_F_GETLK64:
 1068                 error = copyin((void *)args->arg, &linux_flock,
 1069                     sizeof(linux_flock));
 1070                 if (error)
 1071                         return (error);
 1072                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
 1073                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
 1074                 if (error)
 1075                         return (error);
 1076                 bsd_to_linux_flock64(&bsd_flock, &linux_flock);
 1077                 return (copyout(&linux_flock, (void *)args->arg,
 1078                             sizeof(linux_flock)));
 1079 
 1080         case LINUX_F_SETLK64:
 1081                 error = copyin((void *)args->arg, &linux_flock,
 1082                     sizeof(linux_flock));
 1083                 if (error)
 1084                         return (error);
 1085                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
 1086                 return (kern_fcntl(td, args->fd, F_SETLK,
 1087                     (intptr_t)&bsd_flock));
 1088 
 1089         case LINUX_F_SETLKW64:
 1090                 error = copyin((void *)args->arg, &linux_flock,
 1091                     sizeof(linux_flock));
 1092                 if (error)
 1093                         return (error);
 1094                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
 1095                 return (kern_fcntl(td, args->fd, F_SETLKW,
 1096                     (intptr_t)&bsd_flock));
 1097         }
 1098 
 1099         return (fcntl_common(td, args));
 1100 }
 1101 #endif /* __i386__ */
 1102 
 1103 int
 1104 linux_chown(struct thread *td, struct linux_chown_args *args)
 1105 {
 1106         char *path;
 1107         int error;
 1108 
 1109         LCONVPATHEXIST(td, args->path, &path);
 1110 
 1111 #ifdef DEBUG
 1112         if (ldebug(chown))
 1113                 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
 1114 #endif
 1115         error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
 1116         LFREEPATH(path);
 1117         return (error);
 1118 }
 1119 
 1120 int
 1121 linux_lchown(struct thread *td, struct linux_lchown_args *args)
 1122 {
 1123         char *path;
 1124         int error;
 1125 
 1126         LCONVPATHEXIST(td, args->path, &path);
 1127 
 1128 #ifdef DEBUG
 1129         if (ldebug(lchown))
 1130                 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
 1131 #endif
 1132         error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
 1133         LFREEPATH(path);
 1134         return (error);
 1135 }

Cache object: 6b6eb93f6f8a8b3afbb8c990af3b7813


[ 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.