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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 1994-1995 Søren Schmidt
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   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/mman.h>
   45 #include <sys/mount.h>
   46 #include <sys/mutex.h>
   47 #include <sys/namei.h>
   48 #include <sys/selinfo.h>
   49 #include <sys/pipe.h>
   50 #include <sys/proc.h>
   51 #include <sys/stat.h>
   52 #include <sys/sx.h>
   53 #include <sys/syscallsubr.h>
   54 #include <sys/sysproto.h>
   55 #include <sys/tty.h>
   56 #include <sys/unistd.h>
   57 #include <sys/vnode.h>
   58 
   59 #ifdef COMPAT_LINUX32
   60 #include <compat/freebsd32/freebsd32_misc.h>
   61 #include <machine/../linux32/linux.h>
   62 #include <machine/../linux32/linux32_proto.h>
   63 #else
   64 #include <machine/../linux/linux.h>
   65 #include <machine/../linux/linux_proto.h>
   66 #endif
   67 #include <compat/linux/linux_misc.h>
   68 #include <compat/linux/linux_util.h>
   69 #include <compat/linux/linux_file.h>
   70 
   71 static int      linux_common_open(struct thread *, int, const char *, int, int,
   72                     enum uio_seg);
   73 static int      linux_do_accessat(struct thread *t, int, const char *, int, int);
   74 static int      linux_getdents_error(struct thread *, int, int);
   75 
   76 static struct bsd_to_linux_bitmap seal_bitmap[] = {
   77         BITMAP_1t1_LINUX(F_SEAL_SEAL),
   78         BITMAP_1t1_LINUX(F_SEAL_SHRINK),
   79         BITMAP_1t1_LINUX(F_SEAL_GROW),
   80         BITMAP_1t1_LINUX(F_SEAL_WRITE),
   81 };
   82 
   83 #define MFD_HUGETLB_ENTRY(_size)                                        \
   84         {                                                               \
   85                 .bsd_value = MFD_HUGE_##_size,                          \
   86                 .linux_value = LINUX_HUGETLB_FLAG_ENCODE_##_size        \
   87         }
   88 static struct bsd_to_linux_bitmap mfd_bitmap[] = {
   89         BITMAP_1t1_LINUX(MFD_CLOEXEC),
   90         BITMAP_1t1_LINUX(MFD_ALLOW_SEALING),
   91         BITMAP_1t1_LINUX(MFD_HUGETLB),
   92         MFD_HUGETLB_ENTRY(64KB),
   93         MFD_HUGETLB_ENTRY(512KB),
   94         MFD_HUGETLB_ENTRY(1MB),
   95         MFD_HUGETLB_ENTRY(2MB),
   96         MFD_HUGETLB_ENTRY(8MB),
   97         MFD_HUGETLB_ENTRY(16MB),
   98         MFD_HUGETLB_ENTRY(32MB),
   99         MFD_HUGETLB_ENTRY(256MB),
  100         MFD_HUGETLB_ENTRY(512MB),
  101         MFD_HUGETLB_ENTRY(1GB),
  102         MFD_HUGETLB_ENTRY(2GB),
  103         MFD_HUGETLB_ENTRY(16GB),
  104 };
  105 #undef MFD_HUGETLB_ENTRY
  106 
  107 #ifdef LINUX_LEGACY_SYSCALLS
  108 int
  109 linux_creat(struct thread *td, struct linux_creat_args *args)
  110 {
  111         char *path;
  112         int error;
  113 
  114         if (!LUSECONVPATH(td)) {
  115                 return (kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE,
  116                     O_WRONLY | O_CREAT | O_TRUNC, args->mode));
  117         }
  118         LCONVPATHEXIST(args->path, &path);
  119         error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
  120             O_WRONLY | O_CREAT | O_TRUNC, args->mode);
  121         LFREEPATH(path);
  122         return (error);
  123 }
  124 #endif
  125 
  126 static int
  127 linux_common_openflags(int l_flags)
  128 {
  129         int bsd_flags;
  130 
  131         bsd_flags = 0;
  132         switch (l_flags & LINUX_O_ACCMODE) {
  133         case LINUX_O_WRONLY:
  134                 bsd_flags |= O_WRONLY;
  135                 break;
  136         case LINUX_O_RDWR:
  137                 bsd_flags |= O_RDWR;
  138                 break;
  139         default:
  140                 bsd_flags |= O_RDONLY;
  141         }
  142         if (l_flags & LINUX_O_NDELAY)
  143                 bsd_flags |= O_NONBLOCK;
  144         if (l_flags & LINUX_O_APPEND)
  145                 bsd_flags |= O_APPEND;
  146         if (l_flags & LINUX_O_SYNC)
  147                 bsd_flags |= O_FSYNC;
  148         if (l_flags & LINUX_O_CLOEXEC)
  149                 bsd_flags |= O_CLOEXEC;
  150         if (l_flags & LINUX_O_NONBLOCK)
  151                 bsd_flags |= O_NONBLOCK;
  152         if (l_flags & LINUX_O_ASYNC)
  153                 bsd_flags |= O_ASYNC;
  154         if (l_flags & LINUX_O_CREAT)
  155                 bsd_flags |= O_CREAT;
  156         if (l_flags & LINUX_O_TRUNC)
  157                 bsd_flags |= O_TRUNC;
  158         if (l_flags & LINUX_O_EXCL)
  159                 bsd_flags |= O_EXCL;
  160         if (l_flags & LINUX_O_NOCTTY)
  161                 bsd_flags |= O_NOCTTY;
  162         if (l_flags & LINUX_O_DIRECT)
  163                 bsd_flags |= O_DIRECT;
  164         if (l_flags & LINUX_O_NOFOLLOW)
  165                 bsd_flags |= O_NOFOLLOW;
  166         if (l_flags & LINUX_O_DIRECTORY)
  167                 bsd_flags |= O_DIRECTORY;
  168         if (l_flags & LINUX_O_PATH)
  169                 bsd_flags |= O_PATH;
  170         /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
  171         return (bsd_flags);
  172 }
  173 
  174 static int
  175 linux_common_open(struct thread *td, int dirfd, const char *path, int l_flags,
  176     int mode, enum uio_seg seg)
  177 {
  178         struct proc *p = td->td_proc;
  179         struct file *fp;
  180         int fd;
  181         int bsd_flags, error;
  182 
  183         bsd_flags = linux_common_openflags(l_flags);
  184         error = kern_openat(td, dirfd, path, seg, bsd_flags, mode);
  185         if (error != 0) {
  186                 if (error == EMLINK)
  187                         error = ELOOP;
  188                 goto done;
  189         }
  190         if (p->p_flag & P_CONTROLT)
  191                 goto done;
  192         if (bsd_flags & O_NOCTTY)
  193                 goto done;
  194 
  195         /*
  196          * XXX In between kern_openat() and fget(), another process
  197          * having the same filedesc could use that fd without
  198          * checking below.
  199         */
  200         fd = td->td_retval[0];
  201         if (fget(td, fd, &cap_ioctl_rights, &fp) == 0) {
  202                 if (fp->f_type != DTYPE_VNODE) {
  203                         fdrop(fp, td);
  204                         goto done;
  205                 }
  206                 sx_slock(&proctree_lock);
  207                 PROC_LOCK(p);
  208                 if (SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
  209                         PROC_UNLOCK(p);
  210                         sx_sunlock(&proctree_lock);
  211                         /* XXXPJD: Verify if TIOCSCTTY is allowed. */
  212                         (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
  213                             td->td_ucred, td);
  214                 } else {
  215                         PROC_UNLOCK(p);
  216                         sx_sunlock(&proctree_lock);
  217                 }
  218                 fdrop(fp, td);
  219         }
  220 
  221 done:
  222         return (error);
  223 }
  224 
  225 int
  226 linux_openat(struct thread *td, struct linux_openat_args *args)
  227 {
  228         char *path;
  229         int dfd, error;
  230 
  231         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  232         if (!LUSECONVPATH(td)) {
  233                 return (linux_common_open(td, dfd, args->filename, args->flags,
  234                     args->mode, UIO_USERSPACE));
  235         }
  236         if (args->flags & LINUX_O_CREAT)
  237                 LCONVPATH_AT(args->filename, &path, 1, dfd);
  238         else
  239                 LCONVPATH_AT(args->filename, &path, 0, dfd);
  240 
  241         error = linux_common_open(td, dfd, path, args->flags, args->mode,
  242             UIO_SYSSPACE);
  243         LFREEPATH(path);
  244         return (error);
  245 }
  246 
  247 #ifdef LINUX_LEGACY_SYSCALLS
  248 int
  249 linux_open(struct thread *td, struct linux_open_args *args)
  250 {
  251         char *path;
  252         int error;
  253 
  254         if (!LUSECONVPATH(td)) {
  255                 return (linux_common_open(td, AT_FDCWD, args->path, args->flags,
  256                     args->mode, UIO_USERSPACE));
  257         }
  258         if (args->flags & LINUX_O_CREAT)
  259                 LCONVPATHCREAT(args->path, &path);
  260         else
  261                 LCONVPATHEXIST(args->path, &path);
  262 
  263         error = linux_common_open(td, AT_FDCWD, path, args->flags, args->mode,
  264             UIO_SYSSPACE);
  265         LFREEPATH(path);
  266         return (error);
  267 }
  268 #endif
  269 
  270 int
  271 linux_name_to_handle_at(struct thread *td,
  272     struct linux_name_to_handle_at_args *args)
  273 {
  274         static const l_int valid_flags = (LINUX_AT_SYMLINK_FOLLOW |
  275             LINUX_AT_EMPTY_PATH);
  276         static const l_uint fh_size = sizeof(fhandle_t);
  277 
  278         fhandle_t fh;
  279         l_uint fh_bytes;
  280         l_int mount_id;
  281         int error, fd, bsd_flags;
  282 
  283         if (args->flags & ~valid_flags)
  284                 return (EINVAL);
  285 
  286         fd = args->dirfd;
  287         if (fd == LINUX_AT_FDCWD)
  288                 fd = AT_FDCWD;
  289 
  290         bsd_flags = 0;
  291         if (!(args->flags & LINUX_AT_SYMLINK_FOLLOW))
  292                 bsd_flags |= AT_SYMLINK_NOFOLLOW;
  293         if ((args->flags & LINUX_AT_EMPTY_PATH) != 0)
  294                 bsd_flags |= AT_EMPTY_PATH;
  295 
  296         if (!LUSECONVPATH(td)) {
  297                 error = kern_getfhat(td, bsd_flags, fd, args->name,
  298                     UIO_USERSPACE, &fh, UIO_SYSSPACE);
  299         } else {
  300                 char *path;
  301 
  302                 LCONVPATH_AT(args->name, &path, 0, fd);
  303                 error = kern_getfhat(td, bsd_flags, fd, path, UIO_SYSSPACE,
  304                     &fh, UIO_SYSSPACE);
  305                 LFREEPATH(path);
  306         }
  307         if (error != 0)
  308                 return (error);
  309 
  310         /* Emit mount_id -- required before EOVERFLOW case. */
  311         mount_id = (fh.fh_fsid.val[0] ^ fh.fh_fsid.val[1]);
  312         error = copyout(&mount_id, args->mnt_id, sizeof(mount_id));
  313         if (error != 0)
  314                 return (error);
  315 
  316         /* Check if there is room for handle. */
  317         error = copyin(&args->handle->handle_bytes, &fh_bytes,
  318             sizeof(fh_bytes));
  319         if (error != 0)
  320                 return (error);
  321 
  322         if (fh_bytes < fh_size) {
  323                 error = copyout(&fh_size, &args->handle->handle_bytes,
  324                     sizeof(fh_size));
  325                 if (error == 0)
  326                         error = EOVERFLOW;
  327                 return (error);
  328         }
  329 
  330         /* Emit handle. */
  331         mount_id = 0;
  332         /*
  333          * We don't use handle_type for anything yet, but initialize a known
  334          * value.
  335          */
  336         error = copyout(&mount_id, &args->handle->handle_type,
  337             sizeof(mount_id));
  338         if (error != 0)
  339                 return (error);
  340 
  341         error = copyout(&fh, &args->handle->f_handle,
  342             sizeof(fh));
  343         return (error);
  344 }
  345 
  346 int
  347 linux_open_by_handle_at(struct thread *td,
  348     struct linux_open_by_handle_at_args *args)
  349 {
  350         l_uint fh_bytes;
  351         int bsd_flags, error;
  352 
  353         error = copyin(&args->handle->handle_bytes, &fh_bytes,
  354             sizeof(fh_bytes));
  355         if (error != 0)
  356                 return (error);
  357 
  358         if (fh_bytes < sizeof(fhandle_t))
  359                 return (EINVAL);
  360 
  361         bsd_flags = linux_common_openflags(args->flags);
  362         return (kern_fhopen(td, (void *)&args->handle->f_handle, bsd_flags));
  363 }
  364 
  365 int
  366 linux_lseek(struct thread *td, struct linux_lseek_args *args)
  367 {
  368 
  369         return (kern_lseek(td, args->fdes, args->off, args->whence));
  370 }
  371 
  372 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
  373 int
  374 linux_llseek(struct thread *td, struct linux_llseek_args *args)
  375 {
  376         int error;
  377         off_t off;
  378 
  379         off = (args->olow) | (((off_t) args->ohigh) << 32);
  380 
  381         error = kern_lseek(td, args->fd, off, args->whence);
  382         if (error != 0)
  383                 return (error);
  384 
  385         error = copyout(td->td_retval, args->res, sizeof(off_t));
  386         if (error != 0)
  387                 return (error);
  388 
  389         td->td_retval[0] = 0;
  390         return (0);
  391 }
  392 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
  393 
  394 /*
  395  * Note that linux_getdents(2) and linux_getdents64(2) have the same
  396  * arguments. They only differ in the definition of struct dirent they
  397  * operate on.
  398  * Note that linux_readdir(2) is a special case of linux_getdents(2)
  399  * where count is always equals 1, meaning that the buffer is one
  400  * dirent-structure in size and that the code can't handle more anyway.
  401  * Note that linux_readdir(2) can't be implemented by means of linux_getdents(2)
  402  * as in case when the *dent buffer size is equal to 1 linux_getdents(2) will
  403  * trash user stack.
  404  */
  405 
  406 static int
  407 linux_getdents_error(struct thread *td, int fd, int err)
  408 {
  409         struct vnode *vp;
  410         struct file *fp;
  411         int error;
  412 
  413         /* Linux return ENOTDIR in case when fd is not a directory. */
  414         error = getvnode(td, fd, &cap_read_rights, &fp);
  415         if (error != 0)
  416                 return (error);
  417         vp = fp->f_vnode;
  418         if (vp->v_type != VDIR) {
  419                 fdrop(fp, td);
  420                 return (ENOTDIR);
  421         }
  422         fdrop(fp, td);
  423         return (err);
  424 }
  425 
  426 struct l_dirent {
  427         l_ulong         d_ino;
  428         l_off_t         d_off;
  429         l_ushort        d_reclen;
  430         char            d_name[LINUX_NAME_MAX + 1];
  431 };
  432 
  433 struct l_dirent64 {
  434         uint64_t        d_ino;
  435         int64_t         d_off;
  436         l_ushort        d_reclen;
  437         u_char          d_type;
  438         char            d_name[LINUX_NAME_MAX + 1];
  439 };
  440 
  441 /*
  442  * Linux uses the last byte in the dirent buffer to store d_type,
  443  * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
  444  */
  445 #define LINUX_RECLEN(namlen)                                            \
  446     roundup(offsetof(struct l_dirent, d_name) + (namlen) + 2, sizeof(l_ulong))
  447 
  448 #define LINUX_RECLEN64(namlen)                                          \
  449     roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1,         \
  450     sizeof(uint64_t))
  451 
  452 #ifdef LINUX_LEGACY_SYSCALLS
  453 int
  454 linux_getdents(struct thread *td, struct linux_getdents_args *args)
  455 {
  456         struct dirent *bdp;
  457         caddr_t inp, buf;               /* BSD-format */
  458         int len, reclen;                /* BSD-format */
  459         caddr_t outp;                   /* Linux-format */
  460         int resid, linuxreclen;         /* Linux-format */
  461         caddr_t lbuf;                   /* Linux-format */
  462         off_t base;
  463         struct l_dirent *linux_dirent;
  464         int buflen, error;
  465         size_t retval;
  466 
  467         buflen = min(args->count, MAXBSIZE);
  468         buf = malloc(buflen, M_TEMP, M_WAITOK);
  469 
  470         error = kern_getdirentries(td, args->fd, buf, buflen,
  471             &base, NULL, UIO_SYSSPACE);
  472         if (error != 0) {
  473                 error = linux_getdents_error(td, args->fd, error);
  474                 goto out1;
  475         }
  476 
  477         lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
  478 
  479         len = td->td_retval[0];
  480         inp = buf;
  481         outp = (caddr_t)args->dent;
  482         resid = args->count;
  483         retval = 0;
  484 
  485         while (len > 0) {
  486                 bdp = (struct dirent *) inp;
  487                 reclen = bdp->d_reclen;
  488                 linuxreclen = LINUX_RECLEN(bdp->d_namlen);
  489                 /*
  490                  * No more space in the user supplied dirent buffer.
  491                  * Return EINVAL.
  492                  */
  493                 if (resid < linuxreclen) {
  494                         error = EINVAL;
  495                         goto out;
  496                 }
  497 
  498                 linux_dirent = (struct l_dirent*)lbuf;
  499                 linux_dirent->d_ino = bdp->d_fileno;
  500                 linux_dirent->d_off = bdp->d_off;
  501                 linux_dirent->d_reclen = linuxreclen;
  502                 /*
  503                  * Copy d_type to last byte of l_dirent buffer
  504                  */
  505                 lbuf[linuxreclen - 1] = bdp->d_type;
  506                 strlcpy(linux_dirent->d_name, bdp->d_name,
  507                     linuxreclen - offsetof(struct l_dirent, d_name)-1);
  508                 error = copyout(linux_dirent, outp, linuxreclen);
  509                 if (error != 0)
  510                         goto out;
  511 
  512                 inp += reclen;
  513                 base += reclen;
  514                 len -= reclen;
  515 
  516                 retval += linuxreclen;
  517                 outp += linuxreclen;
  518                 resid -= linuxreclen;
  519         }
  520         td->td_retval[0] = retval;
  521 
  522 out:
  523         free(lbuf, M_TEMP);
  524 out1:
  525         free(buf, M_TEMP);
  526         return (error);
  527 }
  528 #endif
  529 
  530 int
  531 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
  532 {
  533         struct dirent *bdp;
  534         caddr_t inp, buf;               /* BSD-format */
  535         int len, reclen;                /* BSD-format */
  536         caddr_t outp;                   /* Linux-format */
  537         int resid, linuxreclen;         /* Linux-format */
  538         caddr_t lbuf;                   /* Linux-format */
  539         off_t base;
  540         struct l_dirent64 *linux_dirent64;
  541         int buflen, error;
  542         size_t retval;
  543 
  544         buflen = min(args->count, MAXBSIZE);
  545         buf = malloc(buflen, M_TEMP, M_WAITOK);
  546 
  547         error = kern_getdirentries(td, args->fd, buf, buflen,
  548             &base, NULL, UIO_SYSSPACE);
  549         if (error != 0) {
  550                 error = linux_getdents_error(td, args->fd, error);
  551                 goto out1;
  552         }
  553 
  554         lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
  555 
  556         len = td->td_retval[0];
  557         inp = buf;
  558         outp = (caddr_t)args->dirent;
  559         resid = args->count;
  560         retval = 0;
  561 
  562         while (len > 0) {
  563                 bdp = (struct dirent *) inp;
  564                 reclen = bdp->d_reclen;
  565                 linuxreclen = LINUX_RECLEN64(bdp->d_namlen);
  566                 /*
  567                  * No more space in the user supplied dirent buffer.
  568                  * Return EINVAL.
  569                  */
  570                 if (resid < linuxreclen) {
  571                         error = EINVAL;
  572                         goto out;
  573                 }
  574 
  575                 linux_dirent64 = (struct l_dirent64*)lbuf;
  576                 linux_dirent64->d_ino = bdp->d_fileno;
  577                 linux_dirent64->d_off = bdp->d_off;
  578                 linux_dirent64->d_reclen = linuxreclen;
  579                 linux_dirent64->d_type = bdp->d_type;
  580                 strlcpy(linux_dirent64->d_name, bdp->d_name,
  581                     linuxreclen - offsetof(struct l_dirent64, d_name));
  582                 error = copyout(linux_dirent64, outp, linuxreclen);
  583                 if (error != 0)
  584                         goto out;
  585 
  586                 inp += reclen;
  587                 base += reclen;
  588                 len -= reclen;
  589 
  590                 retval += linuxreclen;
  591                 outp += linuxreclen;
  592                 resid -= linuxreclen;
  593         }
  594         td->td_retval[0] = retval;
  595 
  596 out:
  597         free(lbuf, M_TEMP);
  598 out1:
  599         free(buf, M_TEMP);
  600         return (error);
  601 }
  602 
  603 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
  604 int
  605 linux_readdir(struct thread *td, struct linux_readdir_args *args)
  606 {
  607         struct dirent *bdp;
  608         caddr_t buf;                    /* BSD-format */
  609         int linuxreclen;                /* Linux-format */
  610         caddr_t lbuf;                   /* Linux-format */
  611         off_t base;
  612         struct l_dirent *linux_dirent;
  613         int buflen, error;
  614 
  615         buflen = LINUX_RECLEN(LINUX_NAME_MAX);
  616         buf = malloc(buflen, M_TEMP, M_WAITOK);
  617 
  618         error = kern_getdirentries(td, args->fd, buf, buflen,
  619             &base, NULL, UIO_SYSSPACE);
  620         if (error != 0) {
  621                 error = linux_getdents_error(td, args->fd, error);
  622                 goto out;
  623         }
  624         if (td->td_retval[0] == 0)
  625                 goto out;
  626 
  627         lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
  628 
  629         bdp = (struct dirent *) buf;
  630         linuxreclen = LINUX_RECLEN(bdp->d_namlen);
  631 
  632         linux_dirent = (struct l_dirent*)lbuf;
  633         linux_dirent->d_ino = bdp->d_fileno;
  634         linux_dirent->d_off = bdp->d_off;
  635         linux_dirent->d_reclen = bdp->d_namlen;
  636         strlcpy(linux_dirent->d_name, bdp->d_name,
  637             linuxreclen - offsetof(struct l_dirent, d_name));
  638         error = copyout(linux_dirent, args->dent, linuxreclen);
  639         if (error == 0)
  640                 td->td_retval[0] = linuxreclen;
  641 
  642         free(lbuf, M_TEMP);
  643 out:
  644         free(buf, M_TEMP);
  645         return (error);
  646 }
  647 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
  648 
  649 /*
  650  * These exist mainly for hooks for doing /compat/linux translation.
  651  */
  652 
  653 #ifdef LINUX_LEGACY_SYSCALLS
  654 int
  655 linux_access(struct thread *td, struct linux_access_args *args)
  656 {
  657         char *path;
  658         int error;
  659 
  660         /* Linux convention. */
  661         if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
  662                 return (EINVAL);
  663 
  664         if (!LUSECONVPATH(td)) {
  665                 error = kern_accessat(td, AT_FDCWD, args->path, UIO_USERSPACE, 0,
  666                     args->amode);
  667         } else {
  668                 LCONVPATHEXIST(args->path, &path);
  669                 error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0,
  670                     args->amode);
  671                 LFREEPATH(path);
  672         }
  673 
  674         return (error);
  675 }
  676 #endif
  677 
  678 static int
  679 linux_do_accessat(struct thread *td, int ldfd, const char *filename,
  680     int amode, int flags)
  681 {
  682         char *path;
  683         int error, dfd;
  684 
  685         /* Linux convention. */
  686         if (amode & ~(F_OK | X_OK | W_OK | R_OK))
  687                 return (EINVAL);
  688 
  689         dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd;
  690         if (!LUSECONVPATH(td)) {
  691                 error = kern_accessat(td, dfd, filename, UIO_USERSPACE, flags, amode);
  692         } else {
  693                 LCONVPATHEXIST_AT(filename, &path, dfd);
  694                 error = kern_accessat(td, dfd, path, UIO_SYSSPACE, flags, amode);
  695                 LFREEPATH(path);
  696         }
  697 
  698         return (error);
  699 }
  700 
  701 int
  702 linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
  703 {
  704 
  705         return (linux_do_accessat(td, args->dfd, args->filename, args->amode,
  706             0));
  707 }
  708 
  709 int
  710 linux_faccessat2(struct thread *td, struct linux_faccessat2_args *args)
  711 {
  712         int flags, unsupported;
  713 
  714         /* XXX. AT_SYMLINK_NOFOLLOW is not supported by kern_accessat */
  715         unsupported = args->flags & ~(LINUX_AT_EACCESS | LINUX_AT_EMPTY_PATH);
  716         if (unsupported != 0) {
  717                 linux_msg(td, "faccessat2 unsupported flag 0x%x", unsupported);
  718                 return (EINVAL);
  719         }
  720 
  721         flags = (args->flags & LINUX_AT_EACCESS) == 0 ? 0 :
  722             AT_EACCESS;
  723         flags |= (args->flags & LINUX_AT_EMPTY_PATH) == 0 ? 0 :
  724             AT_EMPTY_PATH;
  725         return (linux_do_accessat(td, args->dfd, args->filename, args->amode,
  726             flags));
  727 }
  728 
  729 
  730 #ifdef LINUX_LEGACY_SYSCALLS
  731 int
  732 linux_unlink(struct thread *td, struct linux_unlink_args *args)
  733 {
  734         char *path;
  735         int error;
  736         struct stat st;
  737 
  738         if (!LUSECONVPATH(td)) {
  739                 error = kern_funlinkat(td, AT_FDCWD, args->path, FD_NONE,
  740                     UIO_USERSPACE, 0, 0);
  741                 if (error == EPERM) {
  742                         /* Introduce POSIX noncompliant behaviour of Linux */
  743                         if (kern_statat(td, 0, AT_FDCWD, args->path,
  744                             UIO_USERSPACE, &st, NULL) == 0) {
  745                                 if (S_ISDIR(st.st_mode))
  746                                         error = EISDIR;
  747                         }
  748                 }
  749         } else {
  750                 LCONVPATHEXIST(args->path, &path);
  751                 error = kern_funlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0, 0);
  752                 if (error == EPERM) {
  753                         /* Introduce POSIX noncompliant behaviour of Linux */
  754                         if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
  755                             NULL) == 0) {
  756                                 if (S_ISDIR(st.st_mode))
  757                                         error = EISDIR;
  758                         }
  759                 }
  760                 LFREEPATH(path);
  761         }
  762 
  763         return (error);
  764 }
  765 #endif
  766 
  767 static int
  768 linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path,
  769     int dfd, struct linux_unlinkat_args *args)
  770 {
  771         struct stat st;
  772         int error;
  773 
  774         if (args->flag & LINUX_AT_REMOVEDIR)
  775                 error = kern_frmdirat(td, dfd, path, FD_NONE, pathseg, 0);
  776         else
  777                 error = kern_funlinkat(td, dfd, path, FD_NONE, pathseg, 0, 0);
  778         if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
  779                 /* Introduce POSIX noncompliant behaviour of Linux */
  780                 if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
  781                     pathseg, &st, NULL) == 0 && S_ISDIR(st.st_mode))
  782                         error = EISDIR;
  783         }
  784         return (error);
  785 }
  786 
  787 int
  788 linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
  789 {
  790         char *path;
  791         int error, dfd;
  792 
  793         if (args->flag & ~LINUX_AT_REMOVEDIR)
  794                 return (EINVAL);
  795         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  796         if (!LUSECONVPATH(td)) {
  797                 return (linux_unlinkat_impl(td, UIO_USERSPACE, args->pathname,
  798                     dfd, args));
  799         }
  800         LCONVPATHEXIST_AT(args->pathname, &path, dfd);
  801         error = linux_unlinkat_impl(td, UIO_SYSSPACE, path, dfd, args);
  802         LFREEPATH(path);
  803         return (error);
  804 }
  805 int
  806 linux_chdir(struct thread *td, struct linux_chdir_args *args)
  807 {
  808         char *path;
  809         int error;
  810 
  811         if (!LUSECONVPATH(td)) {
  812                 return (kern_chdir(td, args->path, UIO_USERSPACE));
  813         }
  814         LCONVPATHEXIST(args->path, &path);
  815         error = kern_chdir(td, path, UIO_SYSSPACE);
  816         LFREEPATH(path);
  817         return (error);
  818 }
  819 
  820 #ifdef LINUX_LEGACY_SYSCALLS
  821 int
  822 linux_chmod(struct thread *td, struct linux_chmod_args *args)
  823 {
  824         char *path;
  825         int error;
  826 
  827         if (!LUSECONVPATH(td)) {
  828                 return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE,
  829                     args->mode, 0));
  830         }
  831         LCONVPATHEXIST(args->path, &path);
  832         error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode, 0);
  833         LFREEPATH(path);
  834         return (error);
  835 }
  836 #endif
  837 
  838 int
  839 linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
  840 {
  841         char *path;
  842         int error, dfd;
  843 
  844         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  845         if (!LUSECONVPATH(td)) {
  846                 return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE,
  847                     args->mode, 0));
  848         }
  849         LCONVPATHEXIST_AT(args->filename, &path, dfd);
  850         error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
  851         LFREEPATH(path);
  852         return (error);
  853 }
  854 
  855 #ifdef LINUX_LEGACY_SYSCALLS
  856 int
  857 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
  858 {
  859         char *path;
  860         int error;
  861 
  862         if (!LUSECONVPATH(td)) {
  863                 return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode));
  864         }
  865         LCONVPATHCREAT(args->path, &path);
  866         error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode);
  867         LFREEPATH(path);
  868         return (error);
  869 }
  870 #endif
  871 
  872 int
  873 linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
  874 {
  875         char *path;
  876         int error, dfd;
  877 
  878         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
  879         if (!LUSECONVPATH(td)) {
  880                 return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode));
  881         }
  882         LCONVPATHCREAT_AT(args->pathname, &path, dfd);
  883         error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
  884         LFREEPATH(path);
  885         return (error);
  886 }
  887 
  888 #ifdef LINUX_LEGACY_SYSCALLS
  889 int
  890 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
  891 {
  892         char *path;
  893         int error;
  894 
  895         if (!LUSECONVPATH(td)) {
  896                 return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE,
  897                     UIO_USERSPACE, 0));
  898         }
  899         LCONVPATHEXIST(args->path, &path);
  900         error = kern_frmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0);
  901         LFREEPATH(path);
  902         return (error);
  903 }
  904 
  905 int
  906 linux_rename(struct thread *td, struct linux_rename_args *args)
  907 {
  908         char *from, *to;
  909         int error;
  910 
  911         if (!LUSECONVPATH(td)) {
  912                 return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD,
  913                     args->to, UIO_USERSPACE));
  914         }
  915         LCONVPATHEXIST(args->from, &from);
  916         /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
  917         error = linux_emul_convpath(args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
  918         if (to == NULL) {
  919                 LFREEPATH(from);
  920                 return (error);
  921         }
  922         error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
  923         LFREEPATH(from);
  924         LFREEPATH(to);
  925         return (error);
  926 }
  927 #endif
  928 
  929 int
  930 linux_renameat(struct thread *td, struct linux_renameat_args *args)
  931 {
  932         struct linux_renameat2_args renameat2_args = {
  933             .olddfd = args->olddfd,
  934             .oldname = args->oldname,
  935             .newdfd = args->newdfd,
  936             .newname = args->newname,
  937             .flags = 0
  938         };
  939 
  940         return (linux_renameat2(td, &renameat2_args));
  941 }
  942 
  943 int
  944 linux_renameat2(struct thread *td, struct linux_renameat2_args *args)
  945 {
  946         char *from, *to;
  947         int error, olddfd, newdfd;
  948 
  949         if (args->flags != 0) {
  950                 if (args->flags & ~(LINUX_RENAME_EXCHANGE |
  951                     LINUX_RENAME_NOREPLACE | LINUX_RENAME_WHITEOUT))
  952                         return (EINVAL);
  953                 if (args->flags & LINUX_RENAME_EXCHANGE &&
  954                     args->flags & (LINUX_RENAME_NOREPLACE |
  955                     LINUX_RENAME_WHITEOUT))
  956                         return (EINVAL);
  957 #if 0
  958                 /*
  959                  * This spams the console on Ubuntu Focal.
  960                  *
  961                  * What's needed here is a general mechanism to let users know
  962                  * about missing features without hogging the system.
  963                  */
  964                 linux_msg(td, "renameat2 unsupported flags 0x%x",
  965                     args->flags);
  966 #endif
  967                 return (EINVAL);
  968         }
  969 
  970         olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
  971         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
  972         if (!LUSECONVPATH(td)) {
  973                 return (kern_renameat(td, olddfd, args->oldname, newdfd,
  974                     args->newname, UIO_USERSPACE));
  975         }
  976         LCONVPATHEXIST_AT(args->oldname, &from, olddfd);
  977         /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
  978         error = linux_emul_convpath(args->newname, UIO_USERSPACE, &to, 1, newdfd);
  979         if (to == NULL) {
  980                 LFREEPATH(from);
  981                 return (error);
  982         }
  983         error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
  984         LFREEPATH(from);
  985         LFREEPATH(to);
  986         return (error);
  987 }
  988 
  989 #ifdef LINUX_LEGACY_SYSCALLS
  990 int
  991 linux_symlink(struct thread *td, struct linux_symlink_args *args)
  992 {
  993         char *path, *to;
  994         int error;
  995 
  996         if (!LUSECONVPATH(td)) {
  997                 return (kern_symlinkat(td, args->path, AT_FDCWD, args->to,
  998                     UIO_USERSPACE));
  999         }
 1000         LCONVPATHEXIST(args->path, &path);
 1001         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
 1002         error = linux_emul_convpath(args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
 1003         if (to == NULL) {
 1004                 LFREEPATH(path);
 1005                 return (error);
 1006         }
 1007         error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
 1008         LFREEPATH(path);
 1009         LFREEPATH(to);
 1010         return (error);
 1011 }
 1012 #endif
 1013 
 1014 int
 1015 linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
 1016 {
 1017         char *path, *to;
 1018         int error, dfd;
 1019 
 1020         dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
 1021         if (!LUSECONVPATH(td)) {
 1022                 return (kern_symlinkat(td, args->oldname, dfd, args->newname,
 1023                     UIO_USERSPACE));
 1024         }
 1025         LCONVPATHEXIST(args->oldname, &path);
 1026         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
 1027         error = linux_emul_convpath(args->newname, UIO_USERSPACE, &to, 1, dfd);
 1028         if (to == NULL) {
 1029                 LFREEPATH(path);
 1030                 return (error);
 1031         }
 1032         error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
 1033         LFREEPATH(path);
 1034         LFREEPATH(to);
 1035         return (error);
 1036 }
 1037 
 1038 #ifdef LINUX_LEGACY_SYSCALLS
 1039 int
 1040 linux_readlink(struct thread *td, struct linux_readlink_args *args)
 1041 {
 1042         char *name;
 1043         int error;
 1044 
 1045         if (args->count <= 0)
 1046                 return (EINVAL);
 1047 
 1048         if (!LUSECONVPATH(td)) {
 1049                 return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE,
 1050                     args->buf, UIO_USERSPACE, args->count));
 1051         }
 1052         LCONVPATHEXIST(args->name, &name);
 1053         error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
 1054             args->buf, UIO_USERSPACE, args->count);
 1055         LFREEPATH(name);
 1056         return (error);
 1057 }
 1058 #endif
 1059 
 1060 int
 1061 linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
 1062 {
 1063         char *name;
 1064         int error, dfd;
 1065 
 1066         if (args->bufsiz <= 0)
 1067                 return (EINVAL);
 1068 
 1069         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
 1070         if (!LUSECONVPATH(td)) {
 1071                 return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE,
 1072                     args->buf, UIO_USERSPACE, args->bufsiz));
 1073         }
 1074         LCONVPATHEXIST_AT(args->path, &name, dfd);
 1075         error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
 1076             UIO_USERSPACE, args->bufsiz);
 1077         LFREEPATH(name);
 1078         return (error);
 1079 }
 1080 
 1081 int
 1082 linux_truncate(struct thread *td, struct linux_truncate_args *args)
 1083 {
 1084         char *path;
 1085         int error;
 1086 
 1087         if (!LUSECONVPATH(td)) {
 1088                 return (kern_truncate(td, args->path, UIO_USERSPACE, args->length));
 1089         }
 1090         LCONVPATHEXIST(args->path, &path);
 1091         error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
 1092         LFREEPATH(path);
 1093         return (error);
 1094 }
 1095 
 1096 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1097 int
 1098 linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
 1099 {
 1100         char *path;
 1101         off_t length;
 1102         int error;
 1103 
 1104 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1105         length = PAIR32TO64(off_t, args->length);
 1106 #else
 1107         length = args->length;
 1108 #endif
 1109 
 1110         if (!LUSECONVPATH(td)) {
 1111                 return (kern_truncate(td, args->path, UIO_USERSPACE, length));
 1112         }
 1113         LCONVPATHEXIST(args->path, &path);
 1114         error = kern_truncate(td, path, UIO_SYSSPACE, length);
 1115         LFREEPATH(path);
 1116         return (error);
 1117 }
 1118 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 1119 
 1120 int
 1121 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
 1122 {
 1123 
 1124         return (kern_ftruncate(td, args->fd, args->length));
 1125 }
 1126 
 1127 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1128 int
 1129 linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
 1130 {
 1131         off_t length;
 1132 
 1133 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1134         length = PAIR32TO64(off_t, args->length);
 1135 #else
 1136         length = args->length;
 1137 #endif
 1138 
 1139         return (kern_ftruncate(td, args->fd, length));
 1140 }
 1141 #endif
 1142 
 1143 #ifdef LINUX_LEGACY_SYSCALLS
 1144 int
 1145 linux_link(struct thread *td, struct linux_link_args *args)
 1146 {
 1147         char *path, *to;
 1148         int error;
 1149 
 1150         if (!LUSECONVPATH(td)) {
 1151                 return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to,
 1152                     UIO_USERSPACE, AT_SYMLINK_FOLLOW));
 1153         }
 1154         LCONVPATHEXIST(args->path, &path);
 1155         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
 1156         error = linux_emul_convpath(args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
 1157         if (to == NULL) {
 1158                 LFREEPATH(path);
 1159                 return (error);
 1160         }
 1161         error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
 1162             AT_SYMLINK_FOLLOW);
 1163         LFREEPATH(path);
 1164         LFREEPATH(to);
 1165         return (error);
 1166 }
 1167 #endif
 1168 
 1169 int
 1170 linux_linkat(struct thread *td, struct linux_linkat_args *args)
 1171 {
 1172         char *path, *to;
 1173         int error, olddfd, newdfd, flag;
 1174 
 1175         if (args->flag & ~(LINUX_AT_SYMLINK_FOLLOW | LINUX_AT_EMPTY_PATH))
 1176                 return (EINVAL);
 1177 
 1178         flag = (args->flag & LINUX_AT_SYMLINK_FOLLOW) != 0 ? AT_SYMLINK_FOLLOW :
 1179             0;
 1180         flag |= (args->flag & LINUX_AT_EMPTY_PATH) != 0 ? AT_EMPTY_PATH : 0;
 1181 
 1182         olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
 1183         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
 1184         if (!LUSECONVPATH(td)) {
 1185                 return (kern_linkat(td, olddfd, newdfd, args->oldname,
 1186                     args->newname, UIO_USERSPACE, flag));
 1187         }
 1188         LCONVPATHEXIST_AT(args->oldname, &path, olddfd);
 1189         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
 1190         error = linux_emul_convpath(args->newname, UIO_USERSPACE, &to, 1, newdfd);
 1191         if (to == NULL) {
 1192                 LFREEPATH(path);
 1193                 return (error);
 1194         }
 1195         error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, flag);
 1196         LFREEPATH(path);
 1197         LFREEPATH(to);
 1198         return (error);
 1199 }
 1200 
 1201 int
 1202 linux_fdatasync(struct thread *td, struct linux_fdatasync_args *uap)
 1203 {
 1204 
 1205         return (kern_fsync(td, uap->fd, false));
 1206 }
 1207 
 1208 int
 1209 linux_sync_file_range(struct thread *td, struct linux_sync_file_range_args *uap)
 1210 {
 1211         off_t nbytes, offset;
 1212 
 1213 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1214         nbytes = PAIR32TO64(off_t, uap->nbytes);
 1215         offset = PAIR32TO64(off_t, uap->offset);
 1216 #else
 1217         nbytes = uap->nbytes;
 1218         offset = uap->offset;
 1219 #endif
 1220 
 1221         if (offset < 0 || nbytes < 0 ||
 1222             (uap->flags & ~(LINUX_SYNC_FILE_RANGE_WAIT_BEFORE |
 1223             LINUX_SYNC_FILE_RANGE_WRITE |
 1224             LINUX_SYNC_FILE_RANGE_WAIT_AFTER)) != 0) {
 1225                 return (EINVAL);
 1226         }
 1227 
 1228         return (kern_fsync(td, uap->fd, false));
 1229 }
 1230 
 1231 int
 1232 linux_pread(struct thread *td, struct linux_pread_args *uap)
 1233 {
 1234         struct vnode *vp;
 1235         off_t offset;
 1236         int error;
 1237 
 1238 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1239         offset = PAIR32TO64(off_t, uap->offset);
 1240 #else
 1241         offset = uap->offset;
 1242 #endif
 1243 
 1244         error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, offset);
 1245         if (error == 0) {
 1246                 /* This seems to violate POSIX but Linux does it. */
 1247                 error = fgetvp(td, uap->fd, &cap_pread_rights, &vp);
 1248                 if (error != 0)
 1249                         return (error);
 1250                 if (vp->v_type == VDIR)
 1251                         error = EISDIR;
 1252                 vrele(vp);
 1253         }
 1254         return (error);
 1255 }
 1256 
 1257 int
 1258 linux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
 1259 {
 1260         off_t offset;
 1261 
 1262 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1263         offset = PAIR32TO64(off_t, uap->offset);
 1264 #else
 1265         offset = uap->offset;
 1266 #endif
 1267 
 1268         return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset));
 1269 }
 1270 
 1271 #define HALF_LONG_BITS ((sizeof(l_long) * NBBY / 2))
 1272 
 1273 static inline off_t
 1274 pos_from_hilo(unsigned long high, unsigned long low)
 1275 {
 1276 
 1277         return (((off_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low;
 1278 }
 1279 
 1280 int
 1281 linux_preadv(struct thread *td, struct linux_preadv_args *uap)
 1282 {
 1283         struct uio *auio;
 1284         int error;
 1285         off_t offset;
 1286 
 1287         /*
 1288          * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES
 1289          * pos_l and pos_h, respectively, contain the
 1290          * low order and high order 32 bits of offset.
 1291          */
 1292         offset = pos_from_hilo(uap->pos_h, uap->pos_l);
 1293         if (offset < 0)
 1294                 return (EINVAL);
 1295 #ifdef COMPAT_LINUX32
 1296         error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
 1297 #else
 1298         error = copyinuio(uap->vec, uap->vlen, &auio);
 1299 #endif
 1300         if (error != 0)
 1301                 return (error);
 1302         error = kern_preadv(td, uap->fd, auio, offset);
 1303         free(auio, M_IOV);
 1304         return (error);
 1305 }
 1306 
 1307 int
 1308 linux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
 1309 {
 1310         struct uio *auio;
 1311         int error;
 1312         off_t offset;
 1313 
 1314         /*
 1315          * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES
 1316          * pos_l and pos_h, respectively, contain the
 1317          * low order and high order 32 bits of offset.
 1318          */
 1319         offset = pos_from_hilo(uap->pos_h, uap->pos_l);
 1320         if (offset < 0)
 1321                 return (EINVAL);
 1322 #ifdef COMPAT_LINUX32
 1323         error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
 1324 #else
 1325         error = copyinuio(uap->vec, uap->vlen, &auio);
 1326 #endif
 1327         if (error != 0)
 1328                 return (error);
 1329         error = kern_pwritev(td, uap->fd, auio, offset);
 1330         free(auio, M_IOV);
 1331         return (error);
 1332 }
 1333 
 1334 int
 1335 linux_mount(struct thread *td, struct linux_mount_args *args)
 1336 {
 1337         struct mntarg *ma = NULL;
 1338         char *fstypename, *mntonname, *mntfromname, *data;
 1339         int error, fsflags;
 1340 
 1341         fstypename = malloc(MNAMELEN, M_TEMP, M_WAITOK);
 1342         mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
 1343         mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
 1344         data = NULL;
 1345         error = copyinstr(args->filesystemtype, fstypename, MNAMELEN - 1,
 1346             NULL);
 1347         if (error != 0)
 1348                 goto out;
 1349         if (args->specialfile != NULL) {
 1350                 error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
 1351                 if (error != 0)
 1352                         goto out;
 1353         } else {
 1354                 mntfromname[0] = '\0';
 1355         }
 1356         error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
 1357         if (error != 0)
 1358                 goto out;
 1359 
 1360         if (strcmp(fstypename, "ext2") == 0) {
 1361                 strcpy(fstypename, "ext2fs");
 1362         } else if (strcmp(fstypename, "proc") == 0) {
 1363                 strcpy(fstypename, "linprocfs");
 1364         } else if (strcmp(fstypename, "vfat") == 0) {
 1365                 strcpy(fstypename, "msdosfs");
 1366         } else if (strcmp(fstypename, "fuse") == 0 ||
 1367             strncmp(fstypename, "fuse.", 5) == 0) {
 1368                 char *fuse_options, *fuse_option, *fuse_name;
 1369 
 1370                 strcpy(mntfromname, "/dev/fuse");
 1371                 strcpy(fstypename, "fusefs");
 1372                 data = malloc(MNAMELEN, M_TEMP, M_WAITOK);
 1373                 error = copyinstr(args->data, data, MNAMELEN - 1, NULL);
 1374                 if (error != 0)
 1375                         goto out;
 1376 
 1377                 fuse_options = data;
 1378                 while ((fuse_option = strsep(&fuse_options, ",")) != NULL) {
 1379                         fuse_name = strsep(&fuse_option, "=");
 1380                         if (fuse_name == NULL || fuse_option == NULL)
 1381                                 goto out;
 1382                         ma = mount_arg(ma, fuse_name, fuse_option, -1);
 1383                 }
 1384 
 1385                 /*
 1386                  * The FUSE server uses Linux errno values instead of FreeBSD
 1387                  * ones; add a flag to tell fuse(4) to do errno translation.
 1388                  */
 1389                 ma = mount_arg(ma, "linux_errnos", "1", -1);
 1390         }
 1391 
 1392         fsflags = 0;
 1393 
 1394         /*
 1395          * Linux SYNC flag is not included; the closest equivalent
 1396          * FreeBSD has is !ASYNC, which is our default.
 1397          */
 1398         if (args->rwflag & LINUX_MS_RDONLY)
 1399                 fsflags |= MNT_RDONLY;
 1400         if (args->rwflag & LINUX_MS_NOSUID)
 1401                 fsflags |= MNT_NOSUID;
 1402         if (args->rwflag & LINUX_MS_NOEXEC)
 1403                 fsflags |= MNT_NOEXEC;
 1404         if (args->rwflag & LINUX_MS_REMOUNT)
 1405                 fsflags |= MNT_UPDATE;
 1406 
 1407         ma = mount_arg(ma, "fstype", fstypename, -1);
 1408         ma = mount_arg(ma, "fspath", mntonname, -1);
 1409         ma = mount_arg(ma, "from", mntfromname, -1);
 1410         error = kernel_mount(ma, fsflags);
 1411 out:
 1412         free(fstypename, M_TEMP);
 1413         free(mntonname, M_TEMP);
 1414         free(mntfromname, M_TEMP);
 1415         free(data, M_TEMP);
 1416         return (error);
 1417 }
 1418 
 1419 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1420 int
 1421 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
 1422 {
 1423 
 1424         return (kern_unmount(td, args->path, 0));
 1425 }
 1426 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 1427 
 1428 #ifdef LINUX_LEGACY_SYSCALLS
 1429 int
 1430 linux_umount(struct thread *td, struct linux_umount_args *args)
 1431 {
 1432         int flags;
 1433 
 1434         flags = 0;
 1435         if ((args->flags & LINUX_MNT_FORCE) != 0) {
 1436                 args->flags &= ~LINUX_MNT_FORCE;
 1437                 flags |= MNT_FORCE;
 1438         }
 1439         if (args->flags != 0) {
 1440                 linux_msg(td, "unsupported umount2 flags %#x", args->flags);
 1441                 return (EINVAL);
 1442         }
 1443 
 1444         return (kern_unmount(td, args->path, flags));
 1445 }
 1446 #endif
 1447 
 1448 /*
 1449  * fcntl family of syscalls
 1450  */
 1451 
 1452 struct l_flock {
 1453         l_short         l_type;
 1454         l_short         l_whence;
 1455         l_off_t         l_start;
 1456         l_off_t         l_len;
 1457         l_pid_t         l_pid;
 1458 }
 1459 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1460 __packed
 1461 #endif
 1462 ;
 1463 
 1464 static void
 1465 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
 1466 {
 1467         switch (linux_flock->l_type) {
 1468         case LINUX_F_RDLCK:
 1469                 bsd_flock->l_type = F_RDLCK;
 1470                 break;
 1471         case LINUX_F_WRLCK:
 1472                 bsd_flock->l_type = F_WRLCK;
 1473                 break;
 1474         case LINUX_F_UNLCK:
 1475                 bsd_flock->l_type = F_UNLCK;
 1476                 break;
 1477         default:
 1478                 bsd_flock->l_type = -1;
 1479                 break;
 1480         }
 1481         bsd_flock->l_whence = linux_flock->l_whence;
 1482         bsd_flock->l_start = (off_t)linux_flock->l_start;
 1483         bsd_flock->l_len = (off_t)linux_flock->l_len;
 1484         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
 1485         bsd_flock->l_sysid = 0;
 1486 }
 1487 
 1488 static void
 1489 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
 1490 {
 1491         switch (bsd_flock->l_type) {
 1492         case F_RDLCK:
 1493                 linux_flock->l_type = LINUX_F_RDLCK;
 1494                 break;
 1495         case F_WRLCK:
 1496                 linux_flock->l_type = LINUX_F_WRLCK;
 1497                 break;
 1498         case F_UNLCK:
 1499                 linux_flock->l_type = LINUX_F_UNLCK;
 1500                 break;
 1501         }
 1502         linux_flock->l_whence = bsd_flock->l_whence;
 1503         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
 1504         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
 1505         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
 1506 }
 1507 
 1508 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1509 struct l_flock64 {
 1510         l_short         l_type;
 1511         l_short         l_whence;
 1512         l_loff_t        l_start;
 1513         l_loff_t        l_len;
 1514         l_pid_t         l_pid;
 1515 }
 1516 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1517 __packed
 1518 #endif
 1519 ;
 1520 
 1521 static void
 1522 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
 1523 {
 1524         switch (linux_flock->l_type) {
 1525         case LINUX_F_RDLCK:
 1526                 bsd_flock->l_type = F_RDLCK;
 1527                 break;
 1528         case LINUX_F_WRLCK:
 1529                 bsd_flock->l_type = F_WRLCK;
 1530                 break;
 1531         case LINUX_F_UNLCK:
 1532                 bsd_flock->l_type = F_UNLCK;
 1533                 break;
 1534         default:
 1535                 bsd_flock->l_type = -1;
 1536                 break;
 1537         }
 1538         bsd_flock->l_whence = linux_flock->l_whence;
 1539         bsd_flock->l_start = (off_t)linux_flock->l_start;
 1540         bsd_flock->l_len = (off_t)linux_flock->l_len;
 1541         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
 1542         bsd_flock->l_sysid = 0;
 1543 }
 1544 
 1545 static void
 1546 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
 1547 {
 1548         switch (bsd_flock->l_type) {
 1549         case F_RDLCK:
 1550                 linux_flock->l_type = LINUX_F_RDLCK;
 1551                 break;
 1552         case F_WRLCK:
 1553                 linux_flock->l_type = LINUX_F_WRLCK;
 1554                 break;
 1555         case F_UNLCK:
 1556                 linux_flock->l_type = LINUX_F_UNLCK;
 1557                 break;
 1558         }
 1559         linux_flock->l_whence = bsd_flock->l_whence;
 1560         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
 1561         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
 1562         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
 1563 }
 1564 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 1565 
 1566 static int
 1567 fcntl_common(struct thread *td, struct linux_fcntl_args *args)
 1568 {
 1569         struct l_flock linux_flock;
 1570         struct flock bsd_flock;
 1571         struct pipe *fpipe;
 1572         struct file *fp;
 1573         long arg;
 1574         int error, result;
 1575 
 1576         switch (args->cmd) {
 1577         case LINUX_F_DUPFD:
 1578                 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
 1579 
 1580         case LINUX_F_GETFD:
 1581                 return (kern_fcntl(td, args->fd, F_GETFD, 0));
 1582 
 1583         case LINUX_F_SETFD:
 1584                 return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
 1585 
 1586         case LINUX_F_GETFL:
 1587                 error = kern_fcntl(td, args->fd, F_GETFL, 0);
 1588                 result = td->td_retval[0];
 1589                 td->td_retval[0] = 0;
 1590                 if (result & O_RDONLY)
 1591                         td->td_retval[0] |= LINUX_O_RDONLY;
 1592                 if (result & O_WRONLY)
 1593                         td->td_retval[0] |= LINUX_O_WRONLY;
 1594                 if (result & O_RDWR)
 1595                         td->td_retval[0] |= LINUX_O_RDWR;
 1596                 if (result & O_NDELAY)
 1597                         td->td_retval[0] |= LINUX_O_NONBLOCK;
 1598                 if (result & O_APPEND)
 1599                         td->td_retval[0] |= LINUX_O_APPEND;
 1600                 if (result & O_FSYNC)
 1601                         td->td_retval[0] |= LINUX_O_SYNC;
 1602                 if (result & O_ASYNC)
 1603                         td->td_retval[0] |= LINUX_O_ASYNC;
 1604 #ifdef LINUX_O_NOFOLLOW
 1605                 if (result & O_NOFOLLOW)
 1606                         td->td_retval[0] |= LINUX_O_NOFOLLOW;
 1607 #endif
 1608 #ifdef LINUX_O_DIRECT
 1609                 if (result & O_DIRECT)
 1610                         td->td_retval[0] |= LINUX_O_DIRECT;
 1611 #endif
 1612                 return (error);
 1613 
 1614         case LINUX_F_SETFL:
 1615                 arg = 0;
 1616                 if (args->arg & LINUX_O_NDELAY)
 1617                         arg |= O_NONBLOCK;
 1618                 if (args->arg & LINUX_O_APPEND)
 1619                         arg |= O_APPEND;
 1620                 if (args->arg & LINUX_O_SYNC)
 1621                         arg |= O_FSYNC;
 1622                 if (args->arg & LINUX_O_ASYNC)
 1623                         arg |= O_ASYNC;
 1624 #ifdef LINUX_O_NOFOLLOW
 1625                 if (args->arg & LINUX_O_NOFOLLOW)
 1626                         arg |= O_NOFOLLOW;
 1627 #endif
 1628 #ifdef LINUX_O_DIRECT
 1629                 if (args->arg & LINUX_O_DIRECT)
 1630                         arg |= O_DIRECT;
 1631 #endif
 1632                 return (kern_fcntl(td, args->fd, F_SETFL, arg));
 1633 
 1634         case LINUX_F_GETLK:
 1635                 error = copyin((void *)args->arg, &linux_flock,
 1636                     sizeof(linux_flock));
 1637                 if (error)
 1638                         return (error);
 1639                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
 1640                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
 1641                 if (error)
 1642                         return (error);
 1643                 bsd_to_linux_flock(&bsd_flock, &linux_flock);
 1644                 return (copyout(&linux_flock, (void *)args->arg,
 1645                     sizeof(linux_flock)));
 1646 
 1647         case LINUX_F_SETLK:
 1648                 error = copyin((void *)args->arg, &linux_flock,
 1649                     sizeof(linux_flock));
 1650                 if (error)
 1651                         return (error);
 1652                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
 1653                 return (kern_fcntl(td, args->fd, F_SETLK,
 1654                     (intptr_t)&bsd_flock));
 1655 
 1656         case LINUX_F_SETLKW:
 1657                 error = copyin((void *)args->arg, &linux_flock,
 1658                     sizeof(linux_flock));
 1659                 if (error)
 1660                         return (error);
 1661                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
 1662                 return (kern_fcntl(td, args->fd, F_SETLKW,
 1663                      (intptr_t)&bsd_flock));
 1664 
 1665         case LINUX_F_GETOWN:
 1666                 return (kern_fcntl(td, args->fd, F_GETOWN, 0));
 1667 
 1668         case LINUX_F_SETOWN:
 1669                 /*
 1670                  * XXX some Linux applications depend on F_SETOWN having no
 1671                  * significant effect for pipes (SIGIO is not delivered for
 1672                  * pipes under Linux-2.2.35 at least).
 1673                  */
 1674                 error = fget(td, args->fd,
 1675                     &cap_fcntl_rights, &fp);
 1676                 if (error)
 1677                         return (error);
 1678                 if (fp->f_type == DTYPE_PIPE) {
 1679                         fdrop(fp, td);
 1680                         return (EINVAL);
 1681                 }
 1682                 fdrop(fp, td);
 1683 
 1684                 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
 1685 
 1686         case LINUX_F_DUPFD_CLOEXEC:
 1687                 return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
 1688         /*
 1689          * Our F_SEAL_* values match Linux one for maximum compatibility.  So we
 1690          * only needed to account for different values for fcntl(2) commands.
 1691          */
 1692         case LINUX_F_GET_SEALS:
 1693                 error = kern_fcntl(td, args->fd, F_GET_SEALS, 0);
 1694                 if (error != 0)
 1695                         return (error);
 1696                 td->td_retval[0] = bsd_to_linux_bits(td->td_retval[0],
 1697                     seal_bitmap, 0);
 1698                 return (0);
 1699 
 1700         case LINUX_F_ADD_SEALS:
 1701                 return (kern_fcntl(td, args->fd, F_ADD_SEALS,
 1702                     linux_to_bsd_bits(args->arg, seal_bitmap, 0)));
 1703 
 1704         case LINUX_F_GETPIPE_SZ:
 1705                 error = fget(td, args->fd,
 1706                     &cap_fcntl_rights, &fp);
 1707                 if (error != 0)
 1708                         return (error);
 1709                 if (fp->f_type != DTYPE_PIPE) {
 1710                         fdrop(fp, td);
 1711                         return (EINVAL);
 1712                 }
 1713                 fpipe = fp->f_data;
 1714                 td->td_retval[0] = fpipe->pipe_buffer.size;
 1715                 fdrop(fp, td);
 1716                 return (0);
 1717 
 1718         default:
 1719                 linux_msg(td, "unsupported fcntl cmd %d", args->cmd);
 1720                 return (EINVAL);
 1721         }
 1722 }
 1723 
 1724 int
 1725 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
 1726 {
 1727 
 1728         return (fcntl_common(td, args));
 1729 }
 1730 
 1731 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1732 int
 1733 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
 1734 {
 1735         struct l_flock64 linux_flock;
 1736         struct flock bsd_flock;
 1737         struct linux_fcntl_args fcntl_args;
 1738         int error;
 1739 
 1740         switch (args->cmd) {
 1741         case LINUX_F_GETLK64:
 1742                 error = copyin((void *)args->arg, &linux_flock,
 1743                     sizeof(linux_flock));
 1744                 if (error)
 1745                         return (error);
 1746                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
 1747                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
 1748                 if (error)
 1749                         return (error);
 1750                 bsd_to_linux_flock64(&bsd_flock, &linux_flock);
 1751                 return (copyout(&linux_flock, (void *)args->arg,
 1752                             sizeof(linux_flock)));
 1753 
 1754         case LINUX_F_SETLK64:
 1755                 error = copyin((void *)args->arg, &linux_flock,
 1756                     sizeof(linux_flock));
 1757                 if (error)
 1758                         return (error);
 1759                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
 1760                 return (kern_fcntl(td, args->fd, F_SETLK,
 1761                     (intptr_t)&bsd_flock));
 1762 
 1763         case LINUX_F_SETLKW64:
 1764                 error = copyin((void *)args->arg, &linux_flock,
 1765                     sizeof(linux_flock));
 1766                 if (error)
 1767                         return (error);
 1768                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
 1769                 return (kern_fcntl(td, args->fd, F_SETLKW,
 1770                     (intptr_t)&bsd_flock));
 1771         }
 1772 
 1773         fcntl_args.fd = args->fd;
 1774         fcntl_args.cmd = args->cmd;
 1775         fcntl_args.arg = args->arg;
 1776         return (fcntl_common(td, &fcntl_args));
 1777 }
 1778 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 1779 
 1780 #ifdef LINUX_LEGACY_SYSCALLS
 1781 int
 1782 linux_chown(struct thread *td, struct linux_chown_args *args)
 1783 {
 1784         char *path;
 1785         int error;
 1786 
 1787         if (!LUSECONVPATH(td)) {
 1788                 return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
 1789                     args->uid, args->gid, 0));
 1790         }
 1791         LCONVPATHEXIST(args->path, &path);
 1792         error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
 1793             args->gid, 0);
 1794         LFREEPATH(path);
 1795         return (error);
 1796 }
 1797 #endif
 1798 
 1799 int
 1800 linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
 1801 {
 1802         char *path;
 1803         int error, dfd, flag, unsupported;
 1804 
 1805         unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH);
 1806         if (unsupported != 0) {
 1807                 linux_msg(td, "fchownat unsupported flag 0x%x", unsupported);
 1808                 return (EINVAL);
 1809         }
 1810 
 1811         flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
 1812             AT_SYMLINK_NOFOLLOW;
 1813         flag |= (args->flag & LINUX_AT_EMPTY_PATH) == 0 ? 0 :
 1814             AT_EMPTY_PATH;
 1815 
 1816         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
 1817         if (!LUSECONVPATH(td)) {
 1818                 return (kern_fchownat(td, dfd, args->filename, UIO_USERSPACE,
 1819                     args->uid, args->gid, flag));
 1820         }
 1821         LCONVPATHEXIST_AT(args->filename, &path, dfd);
 1822         error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
 1823             flag);
 1824         LFREEPATH(path);
 1825         return (error);
 1826 }
 1827 
 1828 #ifdef LINUX_LEGACY_SYSCALLS
 1829 int
 1830 linux_lchown(struct thread *td, struct linux_lchown_args *args)
 1831 {
 1832         char *path;
 1833         int error;
 1834 
 1835         if (!LUSECONVPATH(td)) {
 1836                 return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid,
 1837                     args->gid, AT_SYMLINK_NOFOLLOW));
 1838         }
 1839         LCONVPATHEXIST(args->path, &path);
 1840         error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid,
 1841             AT_SYMLINK_NOFOLLOW);
 1842         LFREEPATH(path);
 1843         return (error);
 1844 }
 1845 #endif
 1846 
 1847 static int
 1848 convert_fadvice(int advice)
 1849 {
 1850         switch (advice) {
 1851         case LINUX_POSIX_FADV_NORMAL:
 1852                 return (POSIX_FADV_NORMAL);
 1853         case LINUX_POSIX_FADV_RANDOM:
 1854                 return (POSIX_FADV_RANDOM);
 1855         case LINUX_POSIX_FADV_SEQUENTIAL:
 1856                 return (POSIX_FADV_SEQUENTIAL);
 1857         case LINUX_POSIX_FADV_WILLNEED:
 1858                 return (POSIX_FADV_WILLNEED);
 1859         case LINUX_POSIX_FADV_DONTNEED:
 1860                 return (POSIX_FADV_DONTNEED);
 1861         case LINUX_POSIX_FADV_NOREUSE:
 1862                 return (POSIX_FADV_NOREUSE);
 1863         default:
 1864                 return (-1);
 1865         }
 1866 }
 1867 
 1868 int
 1869 linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
 1870 {
 1871         off_t offset;
 1872         int advice;
 1873 
 1874 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1875         offset = PAIR32TO64(off_t, args->offset);
 1876 #else
 1877         offset = args->offset;
 1878 #endif
 1879 
 1880         advice = convert_fadvice(args->advice);
 1881         if (advice == -1)
 1882                 return (EINVAL);
 1883         return (kern_posix_fadvise(td, args->fd, offset, args->len, advice));
 1884 }
 1885 
 1886 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
 1887 int
 1888 linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
 1889 {
 1890         off_t len, offset;
 1891         int advice;
 1892 
 1893 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1894         len = PAIR32TO64(off_t, args->len);
 1895         offset = PAIR32TO64(off_t, args->offset);
 1896 #else
 1897         len = args->len;
 1898         offset = args->offset;
 1899 #endif
 1900 
 1901         advice = convert_fadvice(args->advice);
 1902         if (advice == -1)
 1903                 return (EINVAL);
 1904         return (kern_posix_fadvise(td, args->fd, offset, len, advice));
 1905 }
 1906 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
 1907 
 1908 #ifdef LINUX_LEGACY_SYSCALLS
 1909 int
 1910 linux_pipe(struct thread *td, struct linux_pipe_args *args)
 1911 {
 1912         int fildes[2];
 1913         int error;
 1914 
 1915         error = kern_pipe(td, fildes, 0, NULL, NULL);
 1916         if (error != 0)
 1917                 return (error);
 1918 
 1919         error = copyout(fildes, args->pipefds, sizeof(fildes));
 1920         if (error != 0) {
 1921                 (void)kern_close(td, fildes[0]);
 1922                 (void)kern_close(td, fildes[1]);
 1923         }
 1924 
 1925         return (error);
 1926 }
 1927 #endif
 1928 
 1929 int
 1930 linux_pipe2(struct thread *td, struct linux_pipe2_args *args)
 1931 {
 1932         int fildes[2];
 1933         int error, flags;
 1934 
 1935         if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
 1936                 return (EINVAL);
 1937 
 1938         flags = 0;
 1939         if ((args->flags & LINUX_O_NONBLOCK) != 0)
 1940                 flags |= O_NONBLOCK;
 1941         if ((args->flags & LINUX_O_CLOEXEC) != 0)
 1942                 flags |= O_CLOEXEC;
 1943         error = kern_pipe(td, fildes, flags, NULL, NULL);
 1944         if (error != 0)
 1945                 return (error);
 1946 
 1947         error = copyout(fildes, args->pipefds, sizeof(fildes));
 1948         if (error != 0) {
 1949                 (void)kern_close(td, fildes[0]);
 1950                 (void)kern_close(td, fildes[1]);
 1951         }
 1952 
 1953         return (error);
 1954 }
 1955 
 1956 int
 1957 linux_dup3(struct thread *td, struct linux_dup3_args *args)
 1958 {
 1959         int cmd;
 1960         intptr_t newfd;
 1961 
 1962         if (args->oldfd == args->newfd)
 1963                 return (EINVAL);
 1964         if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
 1965                 return (EINVAL);
 1966         if (args->flags & LINUX_O_CLOEXEC)
 1967                 cmd = F_DUP2FD_CLOEXEC;
 1968         else
 1969                 cmd = F_DUP2FD;
 1970 
 1971         newfd = args->newfd;
 1972         return (kern_fcntl(td, args->oldfd, cmd, newfd));
 1973 }
 1974 
 1975 int
 1976 linux_fallocate(struct thread *td, struct linux_fallocate_args *args)
 1977 {
 1978         off_t len, offset;
 1979 
 1980         /*
 1981          * We emulate only posix_fallocate system call for which
 1982          * mode should be 0.
 1983          */
 1984         if (args->mode != 0)
 1985                 return (EOPNOTSUPP);
 1986 
 1987 #if defined(__amd64__) && defined(COMPAT_LINUX32)
 1988         len = PAIR32TO64(off_t, args->len);
 1989         offset = PAIR32TO64(off_t, args->offset);
 1990 #else
 1991         len = args->len;
 1992         offset = args->offset;
 1993 #endif
 1994 
 1995         return (kern_posix_fallocate(td, args->fd, offset, len));
 1996 }
 1997 
 1998 int
 1999 linux_copy_file_range(struct thread *td, struct linux_copy_file_range_args
 2000     *args)
 2001 {
 2002         l_loff_t inoff, outoff, *inoffp, *outoffp;
 2003         int error, flags;
 2004 
 2005         /*
 2006          * copy_file_range(2) on Linux doesn't define any flags (yet), so is
 2007          * the native implementation.  Enforce it.
 2008          */
 2009         if (args->flags != 0) {
 2010                 linux_msg(td, "copy_file_range unsupported flags 0x%x",
 2011                     args->flags);
 2012                 return (EINVAL);
 2013         }
 2014         flags = 0;
 2015         inoffp = outoffp = NULL;
 2016         if (args->off_in != NULL) {
 2017                 error = copyin(args->off_in, &inoff, sizeof(l_loff_t));
 2018                 if (error != 0)
 2019                         return (error);
 2020                 inoffp = &inoff;
 2021         }
 2022         if (args->off_out != NULL) {
 2023                 error = copyin(args->off_out, &outoff, sizeof(l_loff_t));
 2024                 if (error != 0)
 2025                         return (error);
 2026                 outoffp = &outoff;
 2027         }
 2028 
 2029         error = kern_copy_file_range(td, args->fd_in, inoffp, args->fd_out,
 2030             outoffp, args->len, flags);
 2031         if (error == 0 && args->off_in != NULL)
 2032                 error = copyout(inoffp, args->off_in, sizeof(l_loff_t));
 2033         if (error == 0 && args->off_out != NULL)
 2034                 error = copyout(outoffp, args->off_out, sizeof(l_loff_t));
 2035         return (error);
 2036 }
 2037 
 2038 #define LINUX_MEMFD_PREFIX      "memfd:"
 2039 
 2040 int
 2041 linux_memfd_create(struct thread *td, struct linux_memfd_create_args *args)
 2042 {
 2043         char memfd_name[LINUX_NAME_MAX + 1];
 2044         int error, flags, shmflags, oflags;
 2045 
 2046         /*
 2047          * This is our clever trick to avoid the heap allocation to copy in the
 2048          * uname.  We don't really need to go this far out of our way, but it
 2049          * does keep the rest of this function fairly clean as they don't have
 2050          * to worry about cleanup on the way out.
 2051          */
 2052         error = copyinstr(args->uname_ptr,
 2053             memfd_name + sizeof(LINUX_MEMFD_PREFIX) - 1,
 2054             LINUX_NAME_MAX - sizeof(LINUX_MEMFD_PREFIX) - 1, NULL);
 2055         if (error != 0) {
 2056                 if (error == ENAMETOOLONG)
 2057                         error = EINVAL;
 2058                 return (error);
 2059         }
 2060 
 2061         memcpy(memfd_name, LINUX_MEMFD_PREFIX, sizeof(LINUX_MEMFD_PREFIX) - 1);
 2062         flags = linux_to_bsd_bits(args->flags, mfd_bitmap, 0);
 2063         if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB |
 2064             MFD_HUGE_MASK)) != 0)
 2065                 return (EINVAL);
 2066         /* Size specified but no HUGETLB. */
 2067         if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0)
 2068                 return (EINVAL);
 2069         /* We don't actually support HUGETLB. */
 2070         if ((flags & MFD_HUGETLB) != 0)
 2071                 return (ENOSYS);
 2072         oflags = O_RDWR;
 2073         shmflags = SHM_GROW_ON_WRITE;
 2074         if ((flags & MFD_CLOEXEC) != 0)
 2075                 oflags |= O_CLOEXEC;
 2076         if ((flags & MFD_ALLOW_SEALING) != 0)
 2077                 shmflags |= SHM_ALLOW_SEALING;
 2078         return (kern_shm_open2(td, SHM_ANON, oflags, 0, shmflags, NULL,
 2079             memfd_name));
 2080 }
 2081 
 2082 int
 2083 linux_splice(struct thread *td, struct linux_splice_args *args)
 2084 {
 2085 
 2086         linux_msg(td, "syscall splice not really implemented");
 2087 
 2088         /*
 2089          * splice(2) is documented to return EINVAL in various circumstances;
 2090          * returning it instead of ENOSYS should hint the caller to use fallback
 2091          * instead.
 2092          */
 2093         return (EINVAL);
 2094 }

Cache object: 37b849d62f9665a9da0461aed6804cee


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