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