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

Cache object: c7cbf869cf631c1774ec625f8ae1e693


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