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: releng/10.4/sys/compat/linux/linux_file.c 301424 2016-06-05 06:02:37Z dchagin $");
   31 
   32 #include "opt_compat.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/capsicum.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/malloc.h>
   44 #include <sys/mount.h>
   45 #include <sys/mutex.h>
   46 #include <sys/namei.h>
   47 #include <sys/proc.h>
   48 #include <sys/stat.h>
   49 #include <sys/sx.h>
   50 #include <sys/syscallsubr.h>
   51 #include <sys/sysproto.h>
   52 #include <sys/tty.h>
   53 #include <sys/unistd.h>
   54 #include <sys/vnode.h>
   55 
   56 #include <security/mac/mac_framework.h>
   57 
   58 #ifdef COMPAT_LINUX32
   59 #include <machine/../linux32/linux.h>
   60 #include <machine/../linux32/linux32_proto.h>
   61 #else
   62 #include <machine/../linux/linux.h>
   63 #include <machine/../linux/linux_proto.h>
   64 #endif
   65 #include <compat/linux/linux_misc.h>
   66 #include <compat/linux/linux_util.h>
   67 #include <compat/linux/linux_file.h>
   68 
   69 int
   70 linux_creat(struct thread *td, struct linux_creat_args *args)
   71 {
   72         char *path;
   73         int error;
   74 
   75         LCONVPATHEXIST(td, args->path, &path);
   76 #ifdef DEBUG
   77         if (ldebug(creat))
   78                 printf(ARGS(creat, "%s, %d"), path, args->mode);
   79 #endif
   80         error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
   81             O_WRONLY | O_CREAT | O_TRUNC, args->mode);
   82         LFREEPATH(path);
   83         return (error);
   84 }
   85 
   86 
   87 static int
   88 linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
   89 {
   90         cap_rights_t rights;
   91         struct proc *p = td->td_proc;
   92         struct file *fp;
   93         int fd;
   94         int bsd_flags, error;
   95 
   96         bsd_flags = 0;
   97         switch (l_flags & LINUX_O_ACCMODE) {
   98         case LINUX_O_WRONLY:
   99                 bsd_flags |= O_WRONLY;
  100                 break;
  101         case LINUX_O_RDWR:
  102                 bsd_flags |= O_RDWR;
  103                 break;
  104         default:
  105                 bsd_flags |= O_RDONLY;
  106         }
  107         if (l_flags & LINUX_O_NDELAY)
  108                 bsd_flags |= O_NONBLOCK;
  109         if (l_flags & LINUX_O_APPEND)
  110                 bsd_flags |= O_APPEND;
  111         if (l_flags & LINUX_O_SYNC)
  112                 bsd_flags |= O_FSYNC;
  113         if (l_flags & LINUX_O_NONBLOCK)
  114                 bsd_flags |= O_NONBLOCK;
  115         if (l_flags & LINUX_FASYNC)
  116                 bsd_flags |= O_ASYNC;
  117         if (l_flags & LINUX_O_CREAT)
  118                 bsd_flags |= O_CREAT;
  119         if (l_flags & LINUX_O_TRUNC)
  120                 bsd_flags |= O_TRUNC;
  121         if (l_flags & LINUX_O_EXCL)
  122                 bsd_flags |= O_EXCL;
  123         if (l_flags & LINUX_O_NOCTTY)
  124                 bsd_flags |= O_NOCTTY;
  125         if (l_flags & LINUX_O_DIRECT)
  126                 bsd_flags |= O_DIRECT;
  127         if (l_flags & LINUX_O_NOFOLLOW)
  128                 bsd_flags |= O_NOFOLLOW;
  129         if (l_flags & LINUX_O_DIRECTORY)
  130                 bsd_flags |= O_DIRECTORY;
  131         /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
  132 
  133         error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
  134         if (error != 0)
  135                 goto done;
  136         if (bsd_flags & O_NOCTTY)
  137                 goto done;
  138 
  139         /*
  140          * XXX In between kern_open() and fget(), another process
  141          * having the same filedesc could use that fd without
  142          * checking below.
  143         */
  144         fd = td->td_retval[0];
  145         if (fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp) == 0) {
  146                 if (fp->f_type != DTYPE_VNODE) {
  147                         fdrop(fp, td);
  148                         goto done;
  149                 }
  150                 sx_slock(&proctree_lock);
  151                 PROC_LOCK(p);
  152                 if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
  153                         PROC_UNLOCK(p);
  154                         sx_sunlock(&proctree_lock);
  155                         /* XXXPJD: Verify if TIOCSCTTY is allowed. */
  156                         (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
  157                             td->td_ucred, td);
  158                 } else {
  159                         PROC_UNLOCK(p);
  160                         sx_sunlock(&proctree_lock);
  161                 }
  162                 fdrop(fp, td);
  163         }
  164 
  165 done:
  166 #ifdef DEBUG
  167         if (ldebug(open))
  168                 printf(LMSG("open returns error %d"), error);
  169 #endif
  170         LFREEPATH(path);
  171         return (error);
  172 }
  173 
  174 int
  175 linux_openat(struct thread *td, struct linux_openat_args *args)
  176 {
  177         char *path;
  178         int dfd;
  179 
  180         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  181         if (args->flags & LINUX_O_CREAT)
  182                 LCONVPATH_AT(td, args->filename, &path, 1, dfd);
  183         else
  184                 LCONVPATH_AT(td, args->filename, &path, 0, dfd);
  185 #ifdef DEBUG
  186         if (ldebug(openat))
  187                 printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
  188                     path, args->flags, args->mode);
  189 #endif
  190         return (linux_common_open(td, dfd, path, args->flags, args->mode));
  191 }
  192 
  193 int
  194 linux_open(struct thread *td, struct linux_open_args *args)
  195 {
  196         char *path;
  197 
  198         if (args->flags & LINUX_O_CREAT)
  199                 LCONVPATHCREAT(td, args->path, &path);
  200         else
  201                 LCONVPATHEXIST(td, args->path, &path);
  202 #ifdef DEBUG
  203         if (ldebug(open))
  204                 printf(ARGS(open, "%s, 0x%x, 0x%x"),
  205                     path, args->flags, args->mode);
  206 #endif
  207         return (linux_common_open(td, AT_FDCWD, path, args->flags, args->mode));
  208 }
  209 
  210 int
  211 linux_lseek(struct thread *td, struct linux_lseek_args *args)
  212 {
  213         struct lseek_args /* {
  214                 int fd;
  215                 int pad;
  216                 off_t offset;
  217                 int whence;
  218         } */ tmp_args;
  219         int error;
  220 
  221 #ifdef DEBUG
  222         if (ldebug(lseek))
  223                 printf(ARGS(lseek, "%d, %ld, %d"),
  224                     args->fdes, (long)args->off, args->whence);
  225 #endif
  226         tmp_args.fd = args->fdes;
  227         tmp_args.offset = (off_t)args->off;
  228         tmp_args.whence = args->whence;
  229         error = sys_lseek(td, &tmp_args);
  230         return (error);
  231 }
  232 
  233 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
  234 int
  235 linux_llseek(struct thread *td, struct linux_llseek_args *args)
  236 {
  237         struct lseek_args bsd_args;
  238         int error;
  239         off_t off;
  240 
  241 #ifdef DEBUG
  242         if (ldebug(llseek))
  243                 printf(ARGS(llseek, "%d, %d:%d, %d"),
  244                     args->fd, args->ohigh, args->olow, args->whence);
  245 #endif
  246         off = (args->olow) | (((off_t) args->ohigh) << 32);
  247 
  248         bsd_args.fd = args->fd;
  249         bsd_args.offset = off;
  250         bsd_args.whence = args->whence;
  251 
  252         if ((error = sys_lseek(td, &bsd_args)))
  253                 return (error);
  254 
  255         if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
  256                 return (error);
  257 
  258         td->td_retval[0] = 0;
  259         return (0);
  260 }
  261 
  262 int
  263 linux_readdir(struct thread *td, struct linux_readdir_args *args)
  264 {
  265         struct linux_getdents_args lda;
  266 
  267         lda.fd = args->fd;
  268         lda.dent = args->dent;
  269         lda.count = 1;
  270         return (linux_getdents(td, &lda));
  271 }
  272 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
  273 
  274 /*
  275  * Note that linux_getdents(2) and linux_getdents64(2) have the same
  276  * arguments. They only differ in the definition of struct dirent they
  277  * operate on. We use this to common the code, with the exception of
  278  * accessing struct dirent. Note that linux_readdir(2) is implemented
  279  * by means of linux_getdents(2). In this case we never operate on
  280  * struct dirent64 and thus don't need to handle it...
  281  */
  282 
  283 struct l_dirent {
  284         l_ulong         d_ino;
  285         l_off_t         d_off;
  286         l_ushort        d_reclen;
  287         char            d_name[LINUX_NAME_MAX + 1];
  288 };
  289 
  290 struct l_dirent64 {
  291         uint64_t        d_ino;
  292         int64_t         d_off;
  293         l_ushort        d_reclen;
  294         u_char          d_type;
  295         char            d_name[LINUX_NAME_MAX + 1];
  296 };
  297 
  298 /*
  299  * Linux uses the last byte in the dirent buffer to store d_type,
  300  * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
  301  */
  302 #define LINUX_RECLEN(namlen)                                            \
  303     roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
  304 
  305 #define LINUX_RECLEN64(namlen)                                          \
  306     roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1,         \
  307     sizeof(uint64_t))
  308 
  309 #define LINUX_MAXRECLEN         max(LINUX_RECLEN(LINUX_NAME_MAX),       \
  310                                     LINUX_RECLEN64(LINUX_NAME_MAX))
  311 #define LINUX_DIRBLKSIZ         512
  312 
  313 static int
  314 getdents_common(struct thread *td, struct linux_getdents64_args *args,
  315     int is64bit)
  316 {
  317         struct dirent *bdp;
  318         struct vnode *vp;
  319         caddr_t inp, buf;               /* BSD-format */
  320         int len, reclen;                /* BSD-format */
  321         caddr_t outp;                   /* Linux-format */
  322         int resid, linuxreclen=0;       /* Linux-format */
  323         caddr_t lbuf;                   /* Linux-format */
  324         cap_rights_t rights;
  325         struct file *fp;
  326         struct uio auio;
  327         struct iovec aiov;
  328         off_t off;
  329         struct l_dirent *linux_dirent;
  330         struct l_dirent64 *linux_dirent64;
  331         int buflen, error, eofflag, nbytes, justone;
  332         u_long *cookies = NULL, *cookiep;
  333         int ncookies;
  334 
  335         nbytes = args->count;
  336         if (nbytes == 1) {
  337                 /* readdir(2) case. Always struct dirent. */
  338                 if (is64bit)
  339                         return (EINVAL);
  340                 nbytes = sizeof(*linux_dirent);
  341                 justone = 1;
  342         } else
  343                 justone = 0;
  344 
  345         error = getvnode(td->td_proc->p_fd, args->fd,
  346             cap_rights_init(&rights, CAP_READ), &fp);
  347         if (error != 0)
  348                 return (error);
  349 
  350         if ((fp->f_flag & FREAD) == 0) {
  351                 fdrop(fp, td);
  352                 return (EBADF);
  353         }
  354 
  355         off = foffset_lock(fp, 0);
  356         vp = fp->f_vnode;
  357         if (vp->v_type != VDIR) {
  358                 foffset_unlock(fp, off, 0);
  359                 fdrop(fp, td);
  360                 return (EINVAL);
  361         }
  362 
  363 
  364         buflen = max(LINUX_DIRBLKSIZ, nbytes);
  365         buflen = min(buflen, MAXBSIZE);
  366         buf = malloc(buflen, M_LINUX, M_WAITOK);
  367         lbuf = malloc(LINUX_MAXRECLEN, M_LINUX, M_WAITOK | M_ZERO);
  368         vn_lock(vp, LK_SHARED | LK_RETRY);
  369 
  370         aiov.iov_base = buf;
  371         aiov.iov_len = buflen;
  372         auio.uio_iov = &aiov;
  373         auio.uio_iovcnt = 1;
  374         auio.uio_rw = UIO_READ;
  375         auio.uio_segflg = UIO_SYSSPACE;
  376         auio.uio_td = td;
  377         auio.uio_resid = buflen;
  378         auio.uio_offset = off;
  379 
  380 #ifdef MAC
  381         /*
  382          * Do directory search MAC check using non-cached credentials.
  383          */
  384         if ((error = mac_vnode_check_readdir(td->td_ucred, vp)))
  385                 goto out;
  386 #endif /* MAC */
  387         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
  388                  &cookies)))
  389                 goto out;
  390 
  391         inp = buf;
  392         outp = (caddr_t)args->dirent;
  393         resid = nbytes;
  394         if ((len = buflen - auio.uio_resid) <= 0)
  395                 goto eof;
  396 
  397         cookiep = cookies;
  398 
  399         if (cookies) {
  400                 /*
  401                  * When using cookies, the vfs has the option of reading from
  402                  * a different offset than that supplied (UFS truncates the
  403                  * offset to a block boundary to make sure that it never reads
  404                  * partway through a directory entry, even if the directory
  405                  * has been compacted).
  406                  */
  407                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
  408                         bdp = (struct dirent *) inp;
  409                         len -= bdp->d_reclen;
  410                         inp += bdp->d_reclen;
  411                         cookiep++;
  412                         ncookies--;
  413                 }
  414         }
  415 
  416         while (len > 0) {
  417                 if (cookiep && ncookies == 0)
  418                         break;
  419                 bdp = (struct dirent *) inp;
  420                 reclen = bdp->d_reclen;
  421                 if (reclen & 3) {
  422                         error = EFAULT;
  423                         goto out;
  424                 }
  425 
  426                 if (bdp->d_fileno == 0) {
  427                         inp += reclen;
  428                         if (cookiep) {
  429                                 off = *cookiep++;
  430                                 ncookies--;
  431                         } else
  432                                 off += reclen;
  433 
  434                         len -= reclen;
  435                         continue;
  436                 }
  437 
  438                 linuxreclen = (is64bit)
  439                     ? LINUX_RECLEN64(bdp->d_namlen)
  440                     : LINUX_RECLEN(bdp->d_namlen);
  441 
  442                 if (reclen > len || resid < linuxreclen) {
  443                         outp++;
  444                         break;
  445                 }
  446 
  447                 if (justone) {
  448                         /* readdir(2) case. */
  449                         linux_dirent = (struct l_dirent*)lbuf;
  450                         linux_dirent->d_ino = bdp->d_fileno;
  451                         linux_dirent->d_off = (l_off_t)linuxreclen;
  452                         linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
  453                         strlcpy(linux_dirent->d_name, bdp->d_name,
  454                             linuxreclen - offsetof(struct l_dirent, d_name));
  455                         error = copyout(linux_dirent, outp, linuxreclen);
  456                 }
  457                 if (is64bit) {
  458                         linux_dirent64 = (struct l_dirent64*)lbuf;
  459                         linux_dirent64->d_ino = bdp->d_fileno;
  460                         linux_dirent64->d_off = (cookiep)
  461                             ? (l_off_t)*cookiep
  462                             : (l_off_t)(off + reclen);
  463                         linux_dirent64->d_reclen = (l_ushort)linuxreclen;
  464                         linux_dirent64->d_type = bdp->d_type;
  465                         strlcpy(linux_dirent64->d_name, bdp->d_name,
  466                             linuxreclen - offsetof(struct l_dirent64, d_name));
  467                         error = copyout(linux_dirent64, outp, linuxreclen);
  468                 } else if (!justone) {
  469                         linux_dirent = (struct l_dirent*)lbuf;
  470                         linux_dirent->d_ino = bdp->d_fileno;
  471                         linux_dirent->d_off = (cookiep)
  472                             ? (l_off_t)*cookiep
  473                             : (l_off_t)(off + reclen);
  474                         linux_dirent->d_reclen = (l_ushort)linuxreclen;
  475                         /*
  476                          * Copy d_type to last byte of l_dirent buffer
  477                          */
  478                         lbuf[linuxreclen-1] = bdp->d_type;
  479                         strlcpy(linux_dirent->d_name, bdp->d_name,
  480                             linuxreclen - offsetof(struct l_dirent, d_name)-1);
  481                         error = copyout(linux_dirent, outp, linuxreclen);
  482                 }
  483 
  484                 if (error)
  485                         goto out;
  486 
  487                 inp += reclen;
  488                 if (cookiep) {
  489                         off = *cookiep++;
  490                         ncookies--;
  491                 } else
  492                         off += reclen;
  493 
  494                 outp += linuxreclen;
  495                 resid -= linuxreclen;
  496                 len -= reclen;
  497                 if (justone)
  498                         break;
  499         }
  500 
  501         if (outp == (caddr_t)args->dirent) {
  502                 nbytes = resid;
  503                 goto eof;
  504         }
  505 
  506         if (justone)
  507                 nbytes = resid + linuxreclen;
  508 
  509 eof:
  510         td->td_retval[0] = nbytes - resid;
  511 
  512 out:
  513         free(cookies, M_TEMP);
  514 
  515         VOP_UNLOCK(vp, 0);
  516         foffset_unlock(fp, off, 0);
  517         fdrop(fp, td);
  518         free(buf, M_LINUX);
  519         free(lbuf, M_LINUX);
  520         return (error);
  521 }
  522 
  523 int
  524 linux_getdents(struct thread *td, struct linux_getdents_args *args)
  525 {
  526 
  527 #ifdef DEBUG
  528         if (ldebug(getdents))
  529                 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
  530 #endif
  531 
  532         return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
  533 }
  534 
  535 int
  536 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
  537 {
  538 
  539 #ifdef DEBUG
  540         if (ldebug(getdents64))
  541                 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
  542 #endif
  543 
  544         return (getdents_common(td, args, 1));
  545 }
  546 
  547 /*
  548  * These exist mainly for hooks for doing /compat/linux translation.
  549  */
  550 
  551 int
  552 linux_access(struct thread *td, struct linux_access_args *args)
  553 {
  554         char *path;
  555         int error;
  556 
  557         /* linux convention */
  558         if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
  559                 return (EINVAL);
  560 
  561         LCONVPATHEXIST(td, args->path, &path);
  562 
  563 #ifdef DEBUG
  564         if (ldebug(access))
  565                 printf(ARGS(access, "%s, %d"), path, args->amode);
  566 #endif
  567         error = kern_access(td, path, UIO_SYSSPACE, args->amode);
  568         LFREEPATH(path);
  569 
  570         return (error);
  571 }
  572 
  573 int
  574 linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
  575 {
  576         char *path;
  577         int error, dfd;
  578 
  579         /* linux convention */
  580         if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
  581                 return (EINVAL);
  582 
  583         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  584         LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
  585 
  586 #ifdef DEBUG
  587         if (ldebug(access))
  588                 printf(ARGS(access, "%s, %d"), path, args->amode);
  589 #endif
  590 
  591         error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode);
  592         LFREEPATH(path);
  593 
  594         return (error);
  595 }
  596 
  597 int
  598 linux_unlink(struct thread *td, struct linux_unlink_args *args)
  599 {
  600         char *path;
  601         int error;
  602         struct stat st;
  603 
  604         LCONVPATHEXIST(td, args->path, &path);
  605 
  606 #ifdef DEBUG
  607         if (ldebug(unlink))
  608                 printf(ARGS(unlink, "%s"), path);
  609 #endif
  610 
  611         error = kern_unlink(td, path, UIO_SYSSPACE);
  612         if (error == EPERM)
  613                 /* Introduce POSIX noncompliant behaviour of Linux */
  614                 if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0)
  615                         if (S_ISDIR(st.st_mode))
  616                                 error = EISDIR;
  617         LFREEPATH(path);
  618         return (error);
  619 }
  620 
  621 int
  622 linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
  623 {
  624         char *path;
  625         int error, dfd;
  626         struct stat st;
  627 
  628         if (args->flag & ~LINUX_AT_REMOVEDIR)
  629                 return (EINVAL);
  630 
  631         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  632         LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
  633 
  634 #ifdef DEBUG
  635         if (ldebug(unlinkat))
  636                 printf(ARGS(unlinkat, "%s"), path);
  637 #endif
  638 
  639         if (args->flag & LINUX_AT_REMOVEDIR)
  640                 error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
  641         else
  642                 error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
  643         if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
  644                 /* Introduce POSIX noncompliant behaviour of Linux */
  645                 if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
  646                     UIO_SYSSPACE, &st) == 0 && S_ISDIR(st.st_mode))
  647                         error = EISDIR;
  648         }
  649         LFREEPATH(path);
  650         return (error);
  651 }
  652 int
  653 linux_chdir(struct thread *td, struct linux_chdir_args *args)
  654 {
  655         char *path;
  656         int error;
  657 
  658         LCONVPATHEXIST(td, args->path, &path);
  659 
  660 #ifdef DEBUG
  661         if (ldebug(chdir))
  662                 printf(ARGS(chdir, "%s"), path);
  663 #endif
  664         error = kern_chdir(td, path, UIO_SYSSPACE);
  665         LFREEPATH(path);
  666         return (error);
  667 }
  668 
  669 int
  670 linux_chmod(struct thread *td, struct linux_chmod_args *args)
  671 {
  672         char *path;
  673         int error;
  674 
  675         LCONVPATHEXIST(td, args->path, &path);
  676 
  677 #ifdef DEBUG
  678         if (ldebug(chmod))
  679                 printf(ARGS(chmod, "%s, %d"), path, args->mode);
  680 #endif
  681         error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
  682         LFREEPATH(path);
  683         return (error);
  684 }
  685 
  686 int
  687 linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
  688 {
  689         char *path;
  690         int error, dfd;
  691 
  692         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  693         LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
  694 
  695 #ifdef DEBUG
  696         if (ldebug(fchmodat))
  697                 printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
  698 #endif
  699 
  700         error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
  701         LFREEPATH(path);
  702         return (error);
  703 }
  704 
  705 int
  706 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
  707 {
  708         char *path;
  709         int error;
  710 
  711         LCONVPATHCREAT(td, args->path, &path);
  712 
  713 #ifdef DEBUG
  714         if (ldebug(mkdir))
  715                 printf(ARGS(mkdir, "%s, %d"), path, args->mode);
  716 #endif
  717         error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
  718         LFREEPATH(path);
  719         return (error);
  720 }
  721 
  722 int
  723 linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
  724 {
  725         char *path;
  726         int error, dfd;
  727 
  728         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  729         LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
  730 
  731 #ifdef DEBUG
  732         if (ldebug(mkdirat))
  733                 printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
  734 #endif
  735         error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
  736         LFREEPATH(path);
  737         return (error);
  738 }
  739 
  740 int
  741 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
  742 {
  743         char *path;
  744         int error;
  745 
  746         LCONVPATHEXIST(td, args->path, &path);
  747 
  748 #ifdef DEBUG
  749         if (ldebug(rmdir))
  750                 printf(ARGS(rmdir, "%s"), path);
  751 #endif
  752         error = kern_rmdir(td, path, UIO_SYSSPACE);
  753         LFREEPATH(path);
  754         return (error);
  755 }
  756 
  757 int
  758 linux_rename(struct thread *td, struct linux_rename_args *args)
  759 {
  760         char *from, *to;
  761         int error;
  762 
  763         LCONVPATHEXIST(td, args->from, &from);
  764         /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
  765         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
  766         if (to == NULL) {
  767                 LFREEPATH(from);
  768                 return (error);
  769         }
  770 
  771 #ifdef DEBUG
  772         if (ldebug(rename))
  773                 printf(ARGS(rename, "%s, %s"), from, to);
  774 #endif
  775         error = kern_rename(td, from, to, UIO_SYSSPACE);
  776         LFREEPATH(from);
  777         LFREEPATH(to);
  778         return (error);
  779 }
  780 
  781 int
  782 linux_renameat(struct thread *td, struct linux_renameat_args *args)
  783 {
  784         char *from, *to;
  785         int error, olddfd, newdfd;
  786 
  787         olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
  788         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
  789         LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
  790         /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
  791         error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
  792         if (to == NULL) {
  793                 LFREEPATH(from);
  794                 return (error);
  795         }
  796 
  797 #ifdef DEBUG
  798         if (ldebug(renameat))
  799                 printf(ARGS(renameat, "%s, %s"), from, to);
  800 #endif
  801         error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
  802         LFREEPATH(from);
  803         LFREEPATH(to);
  804         return (error);
  805 }
  806 
  807 int
  808 linux_symlink(struct thread *td, struct linux_symlink_args *args)
  809 {
  810         char *path, *to;
  811         int error;
  812 
  813         LCONVPATHEXIST(td, args->path, &path);
  814         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
  815         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
  816         if (to == NULL) {
  817                 LFREEPATH(path);
  818                 return (error);
  819         }
  820 
  821 #ifdef DEBUG
  822         if (ldebug(symlink))
  823                 printf(ARGS(symlink, "%s, %s"), path, to);
  824 #endif
  825         error = kern_symlink(td, path, to, UIO_SYSSPACE);
  826         LFREEPATH(path);
  827         LFREEPATH(to);
  828         return (error);
  829 }
  830 
  831 int
  832 linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
  833 {
  834         char *path, *to;
  835         int error, dfd;
  836 
  837         dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
  838         LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
  839         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
  840         error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
  841         if (to == NULL) {
  842                 LFREEPATH(path);
  843                 return (error);
  844         }
  845 
  846 #ifdef DEBUG
  847         if (ldebug(symlinkat))
  848                 printf(ARGS(symlinkat, "%s, %s"), path, to);
  849 #endif
  850 
  851         error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
  852         LFREEPATH(path);
  853         LFREEPATH(to);
  854         return (error);
  855 }
  856 
  857 int
  858 linux_readlink(struct thread *td, struct linux_readlink_args *args)
  859 {
  860         char *name;
  861         int error;
  862 
  863         LCONVPATHEXIST(td, args->name, &name);
  864 
  865 #ifdef DEBUG
  866         if (ldebug(readlink))
  867                 printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
  868                     args->count);
  869 #endif
  870         error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
  871             args->count);
  872         LFREEPATH(name);
  873         return (error);
  874 }
  875 
  876 int
  877 linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
  878 {
  879         char *name;
  880         int error, dfd;
  881 
  882         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  883         LCONVPATHEXIST_AT(td, args->path, &name, dfd);
  884 
  885 #ifdef DEBUG
  886         if (ldebug(readlinkat))
  887                 printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
  888                     args->bufsiz);
  889 #endif
  890 
  891         error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
  892             UIO_USERSPACE, args->bufsiz);
  893         LFREEPATH(name);
  894         return (error);
  895 }
  896 
  897 int
  898 linux_truncate(struct thread *td, struct linux_truncate_args *args)
  899 {
  900         char *path;
  901         int error;
  902 
  903         LCONVPATHEXIST(td, args->path, &path);
  904 
  905 #ifdef DEBUG
  906         if (ldebug(truncate))
  907                 printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
  908 #endif
  909 
  910         error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
  911         LFREEPATH(path);
  912         return (error);
  913 }
  914 
  915 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
  916 int
  917 linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
  918 {
  919         char *path;
  920         int error;
  921 
  922         LCONVPATHEXIST(td, args->path, &path);
  923 
  924 #ifdef DEBUG
  925         if (ldebug(truncate64))
  926                 printf(ARGS(truncate64, "%s, %jd"), path, args->length);
  927 #endif
  928 
  929         error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
  930         LFREEPATH(path);
  931         return (error);
  932 }
  933 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
  934 
  935 int
  936 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
  937 {
  938         struct ftruncate_args /* {
  939                 int fd;
  940                 int pad;
  941                 off_t length;
  942                 } */ nuap;
  943 
  944         nuap.fd = args->fd;
  945         nuap.length = args->length;
  946         return (sys_ftruncate(td, &nuap));
  947 }
  948 
  949 int
  950 linux_link(struct thread *td, struct linux_link_args *args)
  951 {
  952         char *path, *to;
  953         int error;
  954 
  955         LCONVPATHEXIST(td, args->path, &path);
  956         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
  957         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
  958         if (to == NULL) {
  959                 LFREEPATH(path);
  960                 return (error);
  961         }
  962 
  963 #ifdef DEBUG
  964         if (ldebug(link))
  965                 printf(ARGS(link, "%s, %s"), path, to);
  966 #endif
  967         error = kern_link(td, path, to, UIO_SYSSPACE);
  968         LFREEPATH(path);
  969         LFREEPATH(to);
  970         return (error);
  971 }
  972 
  973 int
  974 linux_linkat(struct thread *td, struct linux_linkat_args *args)
  975 {
  976         char *path, *to;
  977         int error, olddfd, newdfd, follow;
  978 
  979         if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
  980                 return (EINVAL);
  981 
  982         olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
  983         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
  984         LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
  985         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
  986         error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
  987         if (to == NULL) {
  988                 LFREEPATH(path);
  989                 return (error);
  990         }
  991 
  992 #ifdef DEBUG
  993         if (ldebug(linkat))
  994                 printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
  995                         args->newdfd, to, args->flag);
  996 #endif
  997 
  998         follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
  999             FOLLOW;
 1000         error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
 1001         LFREEPATH(path);
 1002         LFREEPATH(to);
 1003         return (error);
 1004 }
 1005 
 1006 int
 1007 linux_fdatasync(td, uap)
 1008         struct thread *td;
 1009         struct linux_fdatasync_args *uap;
 1010 {
 1011         struct fsync_args bsd;
 1012 
 1013         bsd.fd = uap->fd;
 1014         return (sys_fsync(td, &bsd));
 1015 }
 1016 
 1017 int
 1018 linux_pread(td, uap)
 1019         struct thread *td;
 1020         struct linux_pread_args *uap;
 1021 {
 1022         struct pread_args bsd;
 1023         cap_rights_t rights;
 1024         struct vnode *vp;
 1025         int error;
 1026 
 1027         bsd.fd = uap->fd;
 1028         bsd.buf = uap->buf;
 1029         bsd.nbyte = uap->nbyte;
 1030         bsd.offset = uap->offset;
 1031         error = sys_pread(td, &bsd);
 1032         if (error == 0) {
 1033                 /* This seems to violate POSIX but linux does it */
 1034                 error = fgetvp(td, uap->fd,
 1035                     cap_rights_init(&rights, CAP_PREAD), &vp);
 1036                 if (error != 0)
 1037                         return (error);
 1038                 if (vp->v_type == VDIR) {
 1039                         vrele(vp);
 1040                         return (EISDIR);
 1041                 }
 1042                 vrele(vp);
 1043         }
 1044         return (error);
 1045 }
 1046 
 1047 int
 1048 linux_pwrite(td, uap)
 1049         struct thread *td;
 1050         struct linux_pwrite_args *uap;
 1051 {
 1052         struct pwrite_args bsd;
 1053 
 1054         bsd.fd = uap->fd;
 1055         bsd.buf = uap->buf;
 1056         bsd.nbyte = uap->nbyte;
 1057         bsd.offset = uap->offset;
 1058         return (sys_pwrite(td, &bsd));
 1059 }
 1060 
 1061 int
 1062 linux_mount(struct thread *td, struct linux_mount_args *args)
 1063 {
 1064         char fstypename[MFSNAMELEN];
 1065         char mntonname[MNAMELEN], mntfromname[MNAMELEN];
 1066         int error;
 1067         int fsflags;
 1068 
 1069         error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
 1070             NULL);
 1071         if (error)
 1072                 return (error);
 1073         error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
 1074         if (error)
 1075                 return (error);
 1076         error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
 1077         if (error)
 1078                 return (error);
 1079 
 1080 #ifdef DEBUG
 1081         if (ldebug(mount))
 1082                 printf(ARGS(mount, "%s, %s, %s"),
 1083                     fstypename, mntfromname, mntonname);
 1084 #endif
 1085 
 1086         if (strcmp(fstypename, "ext2") == 0) {
 1087                 strcpy(fstypename, "ext2fs");
 1088         } else if (strcmp(fstypename, "proc") == 0) {
 1089                 strcpy(fstypename, "linprocfs");
 1090         } else if (strcmp(fstypename, "vfat") == 0) {
 1091                 strcpy(fstypename, "msdosfs");
 1092         }
 1093 
 1094         fsflags = 0;
 1095 
 1096         if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
 1097                 /*
 1098                  * Linux SYNC flag is not included; the closest equivalent
 1099                  * FreeBSD has is !ASYNC, which is our default.
 1100                  */
 1101                 if (args->rwflag & LINUX_MS_RDONLY)
 1102                         fsflags |= MNT_RDONLY;
 1103                 if (args->rwflag & LINUX_MS_NOSUID)
 1104                         fsflags |= MNT_NOSUID;
 1105                 if (args->rwflag & LINUX_MS_NOEXEC)
 1106                         fsflags |= MNT_NOEXEC;
 1107                 if (args->rwflag & LINUX_MS_REMOUNT)
 1108                         fsflags |= MNT_UPDATE;
 1109         }
 1110 
 1111         error = kernel_vmount(fsflags,
 1112             "fstype", fstypename,
 1113             "fspath", mntonname,
 1114             "from", mntfromname,
 1115             NULL);
 1116         return (error);
 1117 }
 1118 
 1119 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1120 int
 1121 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
 1122 {
 1123         struct linux_umount_args args2;
 1124 
 1125         args2.path = args->path;
 1126         args2.flags = 0;
 1127         return (linux_umount(td, &args2));
 1128 }
 1129 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 1130 
 1131 int
 1132 linux_umount(struct thread *td, struct linux_umount_args *args)
 1133 {
 1134         struct unmount_args bsd;
 1135 
 1136         bsd.path = args->path;
 1137         bsd.flags = args->flags;        /* XXX correct? */
 1138         return (sys_unmount(td, &bsd));
 1139 }
 1140 
 1141 /*
 1142  * fcntl family of syscalls
 1143  */
 1144 
 1145 struct l_flock {
 1146         l_short         l_type;
 1147         l_short         l_whence;
 1148         l_off_t         l_start;
 1149         l_off_t         l_len;
 1150         l_pid_t         l_pid;
 1151 }
 1152 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1153 __packed
 1154 #endif
 1155 ;
 1156 
 1157 static void
 1158 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
 1159 {
 1160         switch (linux_flock->l_type) {
 1161         case LINUX_F_RDLCK:
 1162                 bsd_flock->l_type = F_RDLCK;
 1163                 break;
 1164         case LINUX_F_WRLCK:
 1165                 bsd_flock->l_type = F_WRLCK;
 1166                 break;
 1167         case LINUX_F_UNLCK:
 1168                 bsd_flock->l_type = F_UNLCK;
 1169                 break;
 1170         default:
 1171                 bsd_flock->l_type = -1;
 1172                 break;
 1173         }
 1174         bsd_flock->l_whence = linux_flock->l_whence;
 1175         bsd_flock->l_start = (off_t)linux_flock->l_start;
 1176         bsd_flock->l_len = (off_t)linux_flock->l_len;
 1177         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
 1178         bsd_flock->l_sysid = 0;
 1179 }
 1180 
 1181 static void
 1182 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
 1183 {
 1184         switch (bsd_flock->l_type) {
 1185         case F_RDLCK:
 1186                 linux_flock->l_type = LINUX_F_RDLCK;
 1187                 break;
 1188         case F_WRLCK:
 1189                 linux_flock->l_type = LINUX_F_WRLCK;
 1190                 break;
 1191         case F_UNLCK:
 1192                 linux_flock->l_type = LINUX_F_UNLCK;
 1193                 break;
 1194         }
 1195         linux_flock->l_whence = bsd_flock->l_whence;
 1196         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
 1197         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
 1198         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
 1199 }
 1200 
 1201 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1202 struct l_flock64 {
 1203         l_short         l_type;
 1204         l_short         l_whence;
 1205         l_loff_t        l_start;
 1206         l_loff_t        l_len;
 1207         l_pid_t         l_pid;
 1208 }
 1209 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1210 __packed
 1211 #endif
 1212 ;
 1213 
 1214 static void
 1215 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
 1216 {
 1217         switch (linux_flock->l_type) {
 1218         case LINUX_F_RDLCK:
 1219                 bsd_flock->l_type = F_RDLCK;
 1220                 break;
 1221         case LINUX_F_WRLCK:
 1222                 bsd_flock->l_type = F_WRLCK;
 1223                 break;
 1224         case LINUX_F_UNLCK:
 1225                 bsd_flock->l_type = F_UNLCK;
 1226                 break;
 1227         default:
 1228                 bsd_flock->l_type = -1;
 1229                 break;
 1230         }
 1231         bsd_flock->l_whence = linux_flock->l_whence;
 1232         bsd_flock->l_start = (off_t)linux_flock->l_start;
 1233         bsd_flock->l_len = (off_t)linux_flock->l_len;
 1234         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
 1235         bsd_flock->l_sysid = 0;
 1236 }
 1237 
 1238 static void
 1239 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
 1240 {
 1241         switch (bsd_flock->l_type) {
 1242         case F_RDLCK:
 1243                 linux_flock->l_type = LINUX_F_RDLCK;
 1244                 break;
 1245         case F_WRLCK:
 1246                 linux_flock->l_type = LINUX_F_WRLCK;
 1247                 break;
 1248         case F_UNLCK:
 1249                 linux_flock->l_type = LINUX_F_UNLCK;
 1250                 break;
 1251         }
 1252         linux_flock->l_whence = bsd_flock->l_whence;
 1253         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
 1254         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
 1255         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
 1256 }
 1257 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 1258 
 1259 static int
 1260 fcntl_common(struct thread *td, struct linux_fcntl_args *args)
 1261 {
 1262         struct l_flock linux_flock;
 1263         struct flock bsd_flock;
 1264         cap_rights_t rights;
 1265         struct file *fp;
 1266         long arg;
 1267         int error, result;
 1268 
 1269         switch (args->cmd) {
 1270         case LINUX_F_DUPFD:
 1271                 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
 1272 
 1273         case LINUX_F_GETFD:
 1274                 return (kern_fcntl(td, args->fd, F_GETFD, 0));
 1275 
 1276         case LINUX_F_SETFD:
 1277                 return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
 1278 
 1279         case LINUX_F_GETFL:
 1280                 error = kern_fcntl(td, args->fd, F_GETFL, 0);
 1281                 result = td->td_retval[0];
 1282                 td->td_retval[0] = 0;
 1283                 if (result & O_RDONLY)
 1284                         td->td_retval[0] |= LINUX_O_RDONLY;
 1285                 if (result & O_WRONLY)
 1286                         td->td_retval[0] |= LINUX_O_WRONLY;
 1287                 if (result & O_RDWR)
 1288                         td->td_retval[0] |= LINUX_O_RDWR;
 1289                 if (result & O_NDELAY)
 1290                         td->td_retval[0] |= LINUX_O_NONBLOCK;
 1291                 if (result & O_APPEND)
 1292                         td->td_retval[0] |= LINUX_O_APPEND;
 1293                 if (result & O_FSYNC)
 1294                         td->td_retval[0] |= LINUX_O_SYNC;
 1295                 if (result & O_ASYNC)
 1296                         td->td_retval[0] |= LINUX_FASYNC;
 1297 #ifdef LINUX_O_NOFOLLOW
 1298                 if (result & O_NOFOLLOW)
 1299                         td->td_retval[0] |= LINUX_O_NOFOLLOW;
 1300 #endif
 1301 #ifdef LINUX_O_DIRECT
 1302                 if (result & O_DIRECT)
 1303                         td->td_retval[0] |= LINUX_O_DIRECT;
 1304 #endif
 1305                 return (error);
 1306 
 1307         case LINUX_F_SETFL:
 1308                 arg = 0;
 1309                 if (args->arg & LINUX_O_NDELAY)
 1310                         arg |= O_NONBLOCK;
 1311                 if (args->arg & LINUX_O_APPEND)
 1312                         arg |= O_APPEND;
 1313                 if (args->arg & LINUX_O_SYNC)
 1314                         arg |= O_FSYNC;
 1315                 if (args->arg & LINUX_FASYNC)
 1316                         arg |= O_ASYNC;
 1317 #ifdef LINUX_O_NOFOLLOW
 1318                 if (args->arg & LINUX_O_NOFOLLOW)
 1319                         arg |= O_NOFOLLOW;
 1320 #endif
 1321 #ifdef LINUX_O_DIRECT
 1322                 if (args->arg & LINUX_O_DIRECT)
 1323                         arg |= O_DIRECT;
 1324 #endif
 1325                 return (kern_fcntl(td, args->fd, F_SETFL, arg));
 1326 
 1327         case LINUX_F_GETLK:
 1328                 error = copyin((void *)args->arg, &linux_flock,
 1329                     sizeof(linux_flock));
 1330                 if (error)
 1331                         return (error);
 1332                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
 1333                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
 1334                 if (error)
 1335                         return (error);
 1336                 bsd_to_linux_flock(&bsd_flock, &linux_flock);
 1337                 return (copyout(&linux_flock, (void *)args->arg,
 1338                     sizeof(linux_flock)));
 1339 
 1340         case LINUX_F_SETLK:
 1341                 error = copyin((void *)args->arg, &linux_flock,
 1342                     sizeof(linux_flock));
 1343                 if (error)
 1344                         return (error);
 1345                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
 1346                 return (kern_fcntl(td, args->fd, F_SETLK,
 1347                     (intptr_t)&bsd_flock));
 1348 
 1349         case LINUX_F_SETLKW:
 1350                 error = copyin((void *)args->arg, &linux_flock,
 1351                     sizeof(linux_flock));
 1352                 if (error)
 1353                         return (error);
 1354                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
 1355                 return (kern_fcntl(td, args->fd, F_SETLKW,
 1356                      (intptr_t)&bsd_flock));
 1357 
 1358         case LINUX_F_GETOWN:
 1359                 return (kern_fcntl(td, args->fd, F_GETOWN, 0));
 1360 
 1361         case LINUX_F_SETOWN:
 1362                 /*
 1363                  * XXX some Linux applications depend on F_SETOWN having no
 1364                  * significant effect for pipes (SIGIO is not delivered for
 1365                  * pipes under Linux-2.2.35 at least).
 1366                  */
 1367                 error = fget(td, args->fd,
 1368                     cap_rights_init(&rights, CAP_FCNTL), &fp);
 1369                 if (error)
 1370                         return (error);
 1371                 if (fp->f_type == DTYPE_PIPE) {
 1372                         fdrop(fp, td);
 1373                         return (EINVAL);
 1374                 }
 1375                 fdrop(fp, td);
 1376 
 1377                 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
 1378 
 1379         case LINUX_F_DUPFD_CLOEXEC:
 1380                 return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
 1381         }
 1382 
 1383         return (EINVAL);
 1384 }
 1385 
 1386 int
 1387 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
 1388 {
 1389 
 1390 #ifdef DEBUG
 1391         if (ldebug(fcntl))
 1392                 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
 1393 #endif
 1394 
 1395         return (fcntl_common(td, args));
 1396 }
 1397 
 1398 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1399 int
 1400 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
 1401 {
 1402         struct l_flock64 linux_flock;
 1403         struct flock bsd_flock;
 1404         struct linux_fcntl_args fcntl_args;
 1405         int error;
 1406 
 1407 #ifdef DEBUG
 1408         if (ldebug(fcntl64))
 1409                 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
 1410 #endif
 1411 
 1412         switch (args->cmd) {
 1413         case LINUX_F_GETLK64:
 1414                 error = copyin((void *)args->arg, &linux_flock,
 1415                     sizeof(linux_flock));
 1416                 if (error)
 1417                         return (error);
 1418                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
 1419                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
 1420                 if (error)
 1421                         return (error);
 1422                 bsd_to_linux_flock64(&bsd_flock, &linux_flock);
 1423                 return (copyout(&linux_flock, (void *)args->arg,
 1424                             sizeof(linux_flock)));
 1425 
 1426         case LINUX_F_SETLK64:
 1427                 error = copyin((void *)args->arg, &linux_flock,
 1428                     sizeof(linux_flock));
 1429                 if (error)
 1430                         return (error);
 1431                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
 1432                 return (kern_fcntl(td, args->fd, F_SETLK,
 1433                     (intptr_t)&bsd_flock));
 1434 
 1435         case LINUX_F_SETLKW64:
 1436                 error = copyin((void *)args->arg, &linux_flock,
 1437                     sizeof(linux_flock));
 1438                 if (error)
 1439                         return (error);
 1440                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
 1441                 return (kern_fcntl(td, args->fd, F_SETLKW,
 1442                     (intptr_t)&bsd_flock));
 1443         }
 1444 
 1445         fcntl_args.fd = args->fd;
 1446         fcntl_args.cmd = args->cmd;
 1447         fcntl_args.arg = args->arg;
 1448         return (fcntl_common(td, &fcntl_args));
 1449 }
 1450 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 1451 
 1452 int
 1453 linux_chown(struct thread *td, struct linux_chown_args *args)
 1454 {
 1455         char *path;
 1456         int error;
 1457 
 1458         LCONVPATHEXIST(td, args->path, &path);
 1459 
 1460 #ifdef DEBUG
 1461         if (ldebug(chown))
 1462                 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
 1463 #endif
 1464         error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
 1465         LFREEPATH(path);
 1466         return (error);
 1467 }
 1468 
 1469 int
 1470 linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
 1471 {
 1472         char *path;
 1473         int error, dfd, flag;
 1474 
 1475         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
 1476                 return (EINVAL);
 1477 
 1478         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
 1479         LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
 1480 
 1481 #ifdef DEBUG
 1482         if (ldebug(fchownat))
 1483                 printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
 1484 #endif
 1485 
 1486         flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
 1487             AT_SYMLINK_NOFOLLOW;
 1488         error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
 1489             flag);
 1490         LFREEPATH(path);
 1491         return (error);
 1492 }
 1493 
 1494 int
 1495 linux_lchown(struct thread *td, struct linux_lchown_args *args)
 1496 {
 1497         char *path;
 1498         int error;
 1499 
 1500         LCONVPATHEXIST(td, args->path, &path);
 1501 
 1502 #ifdef DEBUG
 1503         if (ldebug(lchown))
 1504                 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
 1505 #endif
 1506         error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
 1507         LFREEPATH(path);
 1508         return (error);
 1509 }
 1510 
 1511 static int
 1512 convert_fadvice(int advice)
 1513 {
 1514         switch (advice) {
 1515         case LINUX_POSIX_FADV_NORMAL:
 1516                 return (POSIX_FADV_NORMAL);
 1517         case LINUX_POSIX_FADV_RANDOM:
 1518                 return (POSIX_FADV_RANDOM);
 1519         case LINUX_POSIX_FADV_SEQUENTIAL:
 1520                 return (POSIX_FADV_SEQUENTIAL);
 1521         case LINUX_POSIX_FADV_WILLNEED:
 1522                 return (POSIX_FADV_WILLNEED);
 1523         case LINUX_POSIX_FADV_DONTNEED:
 1524                 return (POSIX_FADV_DONTNEED);
 1525         case LINUX_POSIX_FADV_NOREUSE:
 1526                 return (POSIX_FADV_NOREUSE);
 1527         default:
 1528                 return (-1);
 1529         }
 1530 }
 1531 
 1532 int
 1533 linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
 1534 {
 1535         int advice;
 1536 
 1537         advice = convert_fadvice(args->advice);
 1538         if (advice == -1)
 1539                 return (EINVAL);
 1540         return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
 1541             advice));
 1542 }
 1543 
 1544 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1545 int
 1546 linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
 1547 {
 1548         int advice;
 1549 
 1550         advice = convert_fadvice(args->advice);
 1551         if (advice == -1)
 1552                 return (EINVAL);
 1553         return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
 1554             advice));
 1555 }
 1556 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 1557 
 1558 int
 1559 linux_pipe(struct thread *td, struct linux_pipe_args *args)
 1560 {
 1561         int fildes[2];
 1562         int error;
 1563 
 1564 #ifdef DEBUG
 1565         if (ldebug(pipe))
 1566                 printf(ARGS(pipe, "*"));
 1567 #endif
 1568 
 1569         error = kern_pipe2(td, fildes, 0);
 1570         if (error)
 1571                 return (error);
 1572 
 1573         /* XXX: Close descriptors on error. */
 1574         return (copyout(fildes, args->pipefds, sizeof(fildes)));
 1575 }
 1576 
 1577 int
 1578 linux_pipe2(struct thread *td, struct linux_pipe2_args *args)
 1579 {
 1580         int fildes[2];
 1581         int error, flags;
 1582 
 1583 #ifdef DEBUG
 1584         if (ldebug(pipe2))
 1585                 printf(ARGS(pipe2, "*, %d"), args->flags);
 1586 #endif
 1587 
 1588         if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
 1589                 return (EINVAL);
 1590 
 1591         flags = 0;
 1592         if ((args->flags & LINUX_O_NONBLOCK) != 0)
 1593                 flags |= O_NONBLOCK;
 1594         if ((args->flags & LINUX_O_CLOEXEC) != 0)
 1595                 flags |= O_CLOEXEC;
 1596         error = kern_pipe2(td, fildes, flags);
 1597         if (error)
 1598                 return (error);
 1599 
 1600         /* XXX: Close descriptors on error. */
 1601         return (copyout(fildes, args->pipefds, sizeof(fildes)));
 1602 }
 1603 
 1604 int
 1605 linux_dup3(struct thread *td, struct linux_dup3_args *args)
 1606 {
 1607         int cmd;
 1608         intptr_t newfd;
 1609 
 1610         if (args->oldfd == args->newfd)
 1611                 return (EINVAL);
 1612         if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
 1613                 return (EINVAL);
 1614         if (args->flags & LINUX_O_CLOEXEC)
 1615                 cmd = F_DUP2FD_CLOEXEC;
 1616         else
 1617                 cmd = F_DUP2FD;
 1618 
 1619         newfd = args->newfd;
 1620         return (kern_fcntl(td, args->oldfd, cmd, newfd));
 1621 }
 1622 
 1623 int
 1624 linux_fallocate(struct thread *td, struct linux_fallocate_args *args)
 1625 {
 1626 
 1627         /*
 1628          * We emulate only posix_fallocate system call for which
 1629          * mode should be 0.
 1630          */
 1631         if (args->mode != 0)
 1632                 return (ENOSYS);
 1633 
 1634         return (kern_posix_fallocate(td, args->fd, args->offset,
 1635             args->len));
 1636 }

Cache object: db03d72e0252a368c871bb253e98cb8e


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