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

Cache object: 58a85ee225d19c4992ce5924ef444aa2


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