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

Cache object: a8dd2b862e7d2106072193dcc1dc8656


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