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

Cache object: 0d35e35f78b2ad7cc96a9c577e0f9710


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