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