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