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

Cache object: efbccb32cc58520f3db7b2d523fff191


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