]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linux/linux_file.c
Merge missed sources for lldb-specific TableGen tool.
[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         char *from, *to;
690         int error, olddfd, newdfd;
691
692         olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
693         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
694         LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
695         /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
696         error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
697         if (to == NULL) {
698                 LFREEPATH(from);
699                 return (error);
700         }
701
702         error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
703         LFREEPATH(from);
704         LFREEPATH(to);
705         return (error);
706 }
707
708 #ifdef LINUX_LEGACY_SYSCALLS
709 int
710 linux_symlink(struct thread *td, struct linux_symlink_args *args)
711 {
712         char *path, *to;
713         int error;
714
715         LCONVPATHEXIST(td, args->path, &path);
716         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
717         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
718         if (to == NULL) {
719                 LFREEPATH(path);
720                 return (error);
721         }
722
723         error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
724         LFREEPATH(path);
725         LFREEPATH(to);
726         return (error);
727 }
728 #endif
729
730 int
731 linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
732 {
733         char *path, *to;
734         int error, dfd;
735
736         dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
737         LCONVPATHEXIST(td, args->oldname, &path);
738         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
739         error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
740         if (to == NULL) {
741                 LFREEPATH(path);
742                 return (error);
743         }
744
745         error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
746         LFREEPATH(path);
747         LFREEPATH(to);
748         return (error);
749 }
750
751 #ifdef LINUX_LEGACY_SYSCALLS
752 int
753 linux_readlink(struct thread *td, struct linux_readlink_args *args)
754 {
755         char *name;
756         int error;
757
758         LCONVPATHEXIST(td, args->name, &name);
759
760         error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
761             args->buf, UIO_USERSPACE, args->count);
762         LFREEPATH(name);
763         return (error);
764 }
765 #endif
766
767 int
768 linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
769 {
770         char *name;
771         int error, dfd;
772
773         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
774         LCONVPATHEXIST_AT(td, args->path, &name, dfd);
775
776         error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
777             UIO_USERSPACE, args->bufsiz);
778         LFREEPATH(name);
779         return (error);
780 }
781
782 int
783 linux_truncate(struct thread *td, struct linux_truncate_args *args)
784 {
785         char *path;
786         int error;
787
788         LCONVPATHEXIST(td, args->path, &path);
789
790         error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
791         LFREEPATH(path);
792         return (error);
793 }
794
795 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
796 int
797 linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
798 {
799         char *path;
800         int error;
801
802         LCONVPATHEXIST(td, args->path, &path);
803
804         error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
805         LFREEPATH(path);
806         return (error);
807 }
808 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
809
810 int
811 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
812 {
813
814         return (kern_ftruncate(td, args->fd, args->length));
815 }
816
817 #ifdef LINUX_LEGACY_SYSCALLS
818 int
819 linux_link(struct thread *td, struct linux_link_args *args)
820 {
821         char *path, *to;
822         int error;
823
824         LCONVPATHEXIST(td, args->path, &path);
825         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
826         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
827         if (to == NULL) {
828                 LFREEPATH(path);
829                 return (error);
830         }
831
832         error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
833             FOLLOW);
834         LFREEPATH(path);
835         LFREEPATH(to);
836         return (error);
837 }
838 #endif
839
840 int
841 linux_linkat(struct thread *td, struct linux_linkat_args *args)
842 {
843         char *path, *to;
844         int error, olddfd, newdfd, follow;
845
846         if (args->flag & ~LINUX_AT_SYMLINK_FOLLOW)
847                 return (EINVAL);
848
849         olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
850         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
851         LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
852         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
853         error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
854         if (to == NULL) {
855                 LFREEPATH(path);
856                 return (error);
857         }
858
859         follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
860             FOLLOW;
861         error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
862         LFREEPATH(path);
863         LFREEPATH(to);
864         return (error);
865 }
866
867 int
868 linux_fdatasync(td, uap)
869         struct thread *td;
870         struct linux_fdatasync_args *uap;
871 {
872
873         return (kern_fsync(td, uap->fd, false));
874 }
875
876 int
877 linux_pread(struct thread *td, struct linux_pread_args *uap)
878 {
879         struct vnode *vp;
880         int error;
881
882         error = kern_pread(td, uap->fd, uap->buf, uap->nbyte, uap->offset);
883         if (error == 0) {
884                 /* This seems to violate POSIX but Linux does it. */
885                 error = fgetvp(td, uap->fd, &cap_pread_rights, &vp);
886                 if (error != 0)
887                         return (error);
888                 if (vp->v_type == VDIR) {
889                         vrele(vp);
890                         return (EISDIR);
891                 }
892                 vrele(vp);
893         }
894         return (error);
895 }
896
897 int
898 linux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
899 {
900
901         return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, uap->offset));
902 }
903
904 int
905 linux_preadv(struct thread *td, struct linux_preadv_args *uap)
906 {
907         struct uio *auio;
908         int error;
909         off_t offset;
910
911         /*
912          * According http://man7.org/linux/man-pages/man2/preadv.2.html#NOTES
913          * pos_l and pos_h, respectively, contain the
914          * low order and high order 32 bits of offset.
915          */
916         offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
917             (sizeof(offset) * 4)) | uap->pos_l;
918         if (offset < 0)
919                 return (EINVAL);
920 #ifdef COMPAT_LINUX32
921         error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
922 #else
923         error = copyinuio(uap->vec, uap->vlen, &auio);
924 #endif
925         if (error != 0)
926                 return (error);
927         error = kern_preadv(td, uap->fd, auio, offset);
928         free(auio, M_IOV);
929         return (error);
930 }
931
932 int
933 linux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
934 {
935         struct uio *auio;
936         int error;
937         off_t offset;
938
939         /*
940          * According http://man7.org/linux/man-pages/man2/pwritev.2.html#NOTES
941          * pos_l and pos_h, respectively, contain the
942          * low order and high order 32 bits of offset.
943          */
944         offset = (((off_t)uap->pos_h << (sizeof(offset) * 4)) <<
945             (sizeof(offset) * 4)) | uap->pos_l;
946         if (offset < 0)
947                 return (EINVAL);
948 #ifdef COMPAT_LINUX32
949         error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
950 #else
951         error = copyinuio(uap->vec, uap->vlen, &auio);
952 #endif
953         if (error != 0)
954                 return (error);
955         error = kern_pwritev(td, uap->fd, auio, offset);
956         free(auio, M_IOV);
957         return (error);
958 }
959
960 int
961 linux_mount(struct thread *td, struct linux_mount_args *args)
962 {
963         char fstypename[MFSNAMELEN];
964         char *mntonname, *mntfromname;
965         int error, fsflags;
966
967         mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
968         mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
969         error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
970             NULL);
971         if (error != 0)
972                 goto out;
973         error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
974         if (error != 0)
975                 goto out;
976         error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
977         if (error != 0)
978                 goto out;
979
980         if (strcmp(fstypename, "ext2") == 0) {
981                 strcpy(fstypename, "ext2fs");
982         } else if (strcmp(fstypename, "proc") == 0) {
983                 strcpy(fstypename, "linprocfs");
984         } else if (strcmp(fstypename, "vfat") == 0) {
985                 strcpy(fstypename, "msdosfs");
986         }
987
988         fsflags = 0;
989
990         if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
991                 /*
992                  * Linux SYNC flag is not included; the closest equivalent
993                  * FreeBSD has is !ASYNC, which is our default.
994                  */
995                 if (args->rwflag & LINUX_MS_RDONLY)
996                         fsflags |= MNT_RDONLY;
997                 if (args->rwflag & LINUX_MS_NOSUID)
998                         fsflags |= MNT_NOSUID;
999                 if (args->rwflag & LINUX_MS_NOEXEC)
1000                         fsflags |= MNT_NOEXEC;
1001                 if (args->rwflag & LINUX_MS_REMOUNT)
1002                         fsflags |= MNT_UPDATE;
1003         }
1004
1005         error = kernel_vmount(fsflags,
1006             "fstype", fstypename,
1007             "fspath", mntonname,
1008             "from", mntfromname,
1009             NULL);
1010 out:
1011         free(mntonname, M_TEMP);
1012         free(mntfromname, M_TEMP);
1013         return (error);
1014 }
1015
1016 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1017 int
1018 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
1019 {
1020         struct linux_umount_args args2;
1021
1022         args2.path = args->path;
1023         args2.flags = 0;
1024         return (linux_umount(td, &args2));
1025 }
1026 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1027
1028 #ifdef LINUX_LEGACY_SYSCALLS
1029 int
1030 linux_umount(struct thread *td, struct linux_umount_args *args)
1031 {
1032         struct unmount_args bsd;
1033
1034         bsd.path = args->path;
1035         bsd.flags = args->flags;        /* XXX correct? */
1036         return (sys_unmount(td, &bsd));
1037 }
1038 #endif
1039
1040 /*
1041  * fcntl family of syscalls
1042  */
1043
1044 struct l_flock {
1045         l_short         l_type;
1046         l_short         l_whence;
1047         l_off_t         l_start;
1048         l_off_t         l_len;
1049         l_pid_t         l_pid;
1050 }
1051 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1052 __packed
1053 #endif
1054 ;
1055
1056 static void
1057 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1058 {
1059         switch (linux_flock->l_type) {
1060         case LINUX_F_RDLCK:
1061                 bsd_flock->l_type = F_RDLCK;
1062                 break;
1063         case LINUX_F_WRLCK:
1064                 bsd_flock->l_type = F_WRLCK;
1065                 break;
1066         case LINUX_F_UNLCK:
1067                 bsd_flock->l_type = F_UNLCK;
1068                 break;
1069         default:
1070                 bsd_flock->l_type = -1;
1071                 break;
1072         }
1073         bsd_flock->l_whence = linux_flock->l_whence;
1074         bsd_flock->l_start = (off_t)linux_flock->l_start;
1075         bsd_flock->l_len = (off_t)linux_flock->l_len;
1076         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1077         bsd_flock->l_sysid = 0;
1078 }
1079
1080 static void
1081 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1082 {
1083         switch (bsd_flock->l_type) {
1084         case F_RDLCK:
1085                 linux_flock->l_type = LINUX_F_RDLCK;
1086                 break;
1087         case F_WRLCK:
1088                 linux_flock->l_type = LINUX_F_WRLCK;
1089                 break;
1090         case F_UNLCK:
1091                 linux_flock->l_type = LINUX_F_UNLCK;
1092                 break;
1093         }
1094         linux_flock->l_whence = bsd_flock->l_whence;
1095         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1096         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1097         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1098 }
1099
1100 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1101 struct l_flock64 {
1102         l_short         l_type;
1103         l_short         l_whence;
1104         l_loff_t        l_start;
1105         l_loff_t        l_len;
1106         l_pid_t         l_pid;
1107 }
1108 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1109 __packed
1110 #endif
1111 ;
1112
1113 static void
1114 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1115 {
1116         switch (linux_flock->l_type) {
1117         case LINUX_F_RDLCK:
1118                 bsd_flock->l_type = F_RDLCK;
1119                 break;
1120         case LINUX_F_WRLCK:
1121                 bsd_flock->l_type = F_WRLCK;
1122                 break;
1123         case LINUX_F_UNLCK:
1124                 bsd_flock->l_type = F_UNLCK;
1125                 break;
1126         default:
1127                 bsd_flock->l_type = -1;
1128                 break;
1129         }
1130         bsd_flock->l_whence = linux_flock->l_whence;
1131         bsd_flock->l_start = (off_t)linux_flock->l_start;
1132         bsd_flock->l_len = (off_t)linux_flock->l_len;
1133         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1134         bsd_flock->l_sysid = 0;
1135 }
1136
1137 static void
1138 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1139 {
1140         switch (bsd_flock->l_type) {
1141         case F_RDLCK:
1142                 linux_flock->l_type = LINUX_F_RDLCK;
1143                 break;
1144         case F_WRLCK:
1145                 linux_flock->l_type = LINUX_F_WRLCK;
1146                 break;
1147         case F_UNLCK:
1148                 linux_flock->l_type = LINUX_F_UNLCK;
1149                 break;
1150         }
1151         linux_flock->l_whence = bsd_flock->l_whence;
1152         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1153         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1154         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1155 }
1156 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1157
1158 static int
1159 fcntl_common(struct thread *td, struct linux_fcntl_args *args)
1160 {
1161         struct l_flock linux_flock;
1162         struct flock bsd_flock;
1163         struct file *fp;
1164         long arg;
1165         int error, result;
1166
1167         switch (args->cmd) {
1168         case LINUX_F_DUPFD:
1169                 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
1170
1171         case LINUX_F_GETFD:
1172                 return (kern_fcntl(td, args->fd, F_GETFD, 0));
1173
1174         case LINUX_F_SETFD:
1175                 return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
1176
1177         case LINUX_F_GETFL:
1178                 error = kern_fcntl(td, args->fd, F_GETFL, 0);
1179                 result = td->td_retval[0];
1180                 td->td_retval[0] = 0;
1181                 if (result & O_RDONLY)
1182                         td->td_retval[0] |= LINUX_O_RDONLY;
1183                 if (result & O_WRONLY)
1184                         td->td_retval[0] |= LINUX_O_WRONLY;
1185                 if (result & O_RDWR)
1186                         td->td_retval[0] |= LINUX_O_RDWR;
1187                 if (result & O_NDELAY)
1188                         td->td_retval[0] |= LINUX_O_NONBLOCK;
1189                 if (result & O_APPEND)
1190                         td->td_retval[0] |= LINUX_O_APPEND;
1191                 if (result & O_FSYNC)
1192                         td->td_retval[0] |= LINUX_O_SYNC;
1193                 if (result & O_ASYNC)
1194                         td->td_retval[0] |= LINUX_FASYNC;
1195 #ifdef LINUX_O_NOFOLLOW
1196                 if (result & O_NOFOLLOW)
1197                         td->td_retval[0] |= LINUX_O_NOFOLLOW;
1198 #endif
1199 #ifdef LINUX_O_DIRECT
1200                 if (result & O_DIRECT)
1201                         td->td_retval[0] |= LINUX_O_DIRECT;
1202 #endif
1203                 return (error);
1204
1205         case LINUX_F_SETFL:
1206                 arg = 0;
1207                 if (args->arg & LINUX_O_NDELAY)
1208                         arg |= O_NONBLOCK;
1209                 if (args->arg & LINUX_O_APPEND)
1210                         arg |= O_APPEND;
1211                 if (args->arg & LINUX_O_SYNC)
1212                         arg |= O_FSYNC;
1213                 if (args->arg & LINUX_FASYNC)
1214                         arg |= O_ASYNC;
1215 #ifdef LINUX_O_NOFOLLOW
1216                 if (args->arg & LINUX_O_NOFOLLOW)
1217                         arg |= O_NOFOLLOW;
1218 #endif
1219 #ifdef LINUX_O_DIRECT
1220                 if (args->arg & LINUX_O_DIRECT)
1221                         arg |= O_DIRECT;
1222 #endif
1223                 return (kern_fcntl(td, args->fd, F_SETFL, arg));
1224
1225         case LINUX_F_GETLK:
1226                 error = copyin((void *)args->arg, &linux_flock,
1227                     sizeof(linux_flock));
1228                 if (error)
1229                         return (error);
1230                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
1231                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1232                 if (error)
1233                         return (error);
1234                 bsd_to_linux_flock(&bsd_flock, &linux_flock);
1235                 return (copyout(&linux_flock, (void *)args->arg,
1236                     sizeof(linux_flock)));
1237
1238         case LINUX_F_SETLK:
1239                 error = copyin((void *)args->arg, &linux_flock,
1240                     sizeof(linux_flock));
1241                 if (error)
1242                         return (error);
1243                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
1244                 return (kern_fcntl(td, args->fd, F_SETLK,
1245                     (intptr_t)&bsd_flock));
1246
1247         case LINUX_F_SETLKW:
1248                 error = copyin((void *)args->arg, &linux_flock,
1249                     sizeof(linux_flock));
1250                 if (error)
1251                         return (error);
1252                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
1253                 return (kern_fcntl(td, args->fd, F_SETLKW,
1254                      (intptr_t)&bsd_flock));
1255
1256         case LINUX_F_GETOWN:
1257                 return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1258
1259         case LINUX_F_SETOWN:
1260                 /*
1261                  * XXX some Linux applications depend on F_SETOWN having no
1262                  * significant effect for pipes (SIGIO is not delivered for
1263                  * pipes under Linux-2.2.35 at least).
1264                  */
1265                 error = fget(td, args->fd,
1266                     &cap_fcntl_rights, &fp);
1267                 if (error)
1268                         return (error);
1269                 if (fp->f_type == DTYPE_PIPE) {
1270                         fdrop(fp, td);
1271                         return (EINVAL);
1272                 }
1273                 fdrop(fp, td);
1274
1275                 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1276
1277         case LINUX_F_DUPFD_CLOEXEC:
1278                 return (kern_fcntl(td, args->fd, F_DUPFD_CLOEXEC, args->arg));
1279         }
1280
1281         return (EINVAL);
1282 }
1283
1284 int
1285 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1286 {
1287
1288         return (fcntl_common(td, args));
1289 }
1290
1291 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1292 int
1293 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1294 {
1295         struct l_flock64 linux_flock;
1296         struct flock bsd_flock;
1297         struct linux_fcntl_args fcntl_args;
1298         int error;
1299
1300         switch (args->cmd) {
1301         case LINUX_F_GETLK64:
1302                 error = copyin((void *)args->arg, &linux_flock,
1303                     sizeof(linux_flock));
1304                 if (error)
1305                         return (error);
1306                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1307                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1308                 if (error)
1309                         return (error);
1310                 bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1311                 return (copyout(&linux_flock, (void *)args->arg,
1312                             sizeof(linux_flock)));
1313
1314         case LINUX_F_SETLK64:
1315                 error = copyin((void *)args->arg, &linux_flock,
1316                     sizeof(linux_flock));
1317                 if (error)
1318                         return (error);
1319                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1320                 return (kern_fcntl(td, args->fd, F_SETLK,
1321                     (intptr_t)&bsd_flock));
1322
1323         case LINUX_F_SETLKW64:
1324                 error = copyin((void *)args->arg, &linux_flock,
1325                     sizeof(linux_flock));
1326                 if (error)
1327                         return (error);
1328                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1329                 return (kern_fcntl(td, args->fd, F_SETLKW,
1330                     (intptr_t)&bsd_flock));
1331         }
1332
1333         fcntl_args.fd = args->fd;
1334         fcntl_args.cmd = args->cmd;
1335         fcntl_args.arg = args->arg;
1336         return (fcntl_common(td, &fcntl_args));
1337 }
1338 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1339
1340 #ifdef LINUX_LEGACY_SYSCALLS
1341 int
1342 linux_chown(struct thread *td, struct linux_chown_args *args)
1343 {
1344         char *path;
1345         int error;
1346
1347         LCONVPATHEXIST(td, args->path, &path);
1348
1349         error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1350             args->gid, 0);
1351         LFREEPATH(path);
1352         return (error);
1353 }
1354 #endif
1355
1356 int
1357 linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
1358 {
1359         char *path;
1360         int error, dfd, flag;
1361
1362         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1363                 return (EINVAL);
1364
1365         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD :  args->dfd;
1366         LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
1367
1368         flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1369             AT_SYMLINK_NOFOLLOW;
1370         error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
1371             flag);
1372         LFREEPATH(path);
1373         return (error);
1374 }
1375
1376 #ifdef LINUX_LEGACY_SYSCALLS
1377 int
1378 linux_lchown(struct thread *td, struct linux_lchown_args *args)
1379 {
1380         char *path;
1381         int error;
1382
1383         LCONVPATHEXIST(td, args->path, &path);
1384
1385         error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
1386             args->gid, AT_SYMLINK_NOFOLLOW);
1387         LFREEPATH(path);
1388         return (error);
1389 }
1390 #endif
1391
1392 static int
1393 convert_fadvice(int advice)
1394 {
1395         switch (advice) {
1396         case LINUX_POSIX_FADV_NORMAL:
1397                 return (POSIX_FADV_NORMAL);
1398         case LINUX_POSIX_FADV_RANDOM:
1399                 return (POSIX_FADV_RANDOM);
1400         case LINUX_POSIX_FADV_SEQUENTIAL:
1401                 return (POSIX_FADV_SEQUENTIAL);
1402         case LINUX_POSIX_FADV_WILLNEED:
1403                 return (POSIX_FADV_WILLNEED);
1404         case LINUX_POSIX_FADV_DONTNEED:
1405                 return (POSIX_FADV_DONTNEED);
1406         case LINUX_POSIX_FADV_NOREUSE:
1407                 return (POSIX_FADV_NOREUSE);
1408         default:
1409                 return (-1);
1410         }
1411 }
1412
1413 int
1414 linux_fadvise64(struct thread *td, struct linux_fadvise64_args *args)
1415 {
1416         int advice;
1417
1418         advice = convert_fadvice(args->advice);
1419         if (advice == -1)
1420                 return (EINVAL);
1421         return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1422             advice));
1423 }
1424
1425 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1426 int
1427 linux_fadvise64_64(struct thread *td, struct linux_fadvise64_64_args *args)
1428 {
1429         int advice;
1430
1431         advice = convert_fadvice(args->advice);
1432         if (advice == -1)
1433                 return (EINVAL);
1434         return (kern_posix_fadvise(td, args->fd, args->offset, args->len,
1435             advice));
1436 }
1437 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1438
1439 #ifdef LINUX_LEGACY_SYSCALLS
1440 int
1441 linux_pipe(struct thread *td, struct linux_pipe_args *args)
1442 {
1443         int fildes[2];
1444         int error;
1445
1446         error = kern_pipe(td, fildes, 0, NULL, NULL);
1447         if (error != 0)
1448                 return (error);
1449
1450         error = copyout(fildes, args->pipefds, sizeof(fildes));
1451         if (error != 0) {
1452                 (void)kern_close(td, fildes[0]);
1453                 (void)kern_close(td, fildes[1]);
1454         }
1455
1456         return (error);
1457 }
1458 #endif
1459
1460 int
1461 linux_pipe2(struct thread *td, struct linux_pipe2_args *args)
1462 {
1463         int fildes[2];
1464         int error, flags;
1465
1466         if ((args->flags & ~(LINUX_O_NONBLOCK | LINUX_O_CLOEXEC)) != 0)
1467                 return (EINVAL);
1468
1469         flags = 0;
1470         if ((args->flags & LINUX_O_NONBLOCK) != 0)
1471                 flags |= O_NONBLOCK;
1472         if ((args->flags & LINUX_O_CLOEXEC) != 0)
1473                 flags |= O_CLOEXEC;
1474         error = kern_pipe(td, fildes, flags, NULL, NULL);
1475         if (error != 0)
1476                 return (error);
1477
1478         error = copyout(fildes, args->pipefds, sizeof(fildes));
1479         if (error != 0) {
1480                 (void)kern_close(td, fildes[0]);
1481                 (void)kern_close(td, fildes[1]);
1482         }
1483
1484         return (error);
1485 }
1486
1487 int
1488 linux_dup3(struct thread *td, struct linux_dup3_args *args)
1489 {
1490         int cmd;
1491         intptr_t newfd;
1492
1493         if (args->oldfd == args->newfd)
1494                 return (EINVAL);
1495         if ((args->flags & ~LINUX_O_CLOEXEC) != 0)
1496                 return (EINVAL);
1497         if (args->flags & LINUX_O_CLOEXEC)
1498                 cmd = F_DUP2FD_CLOEXEC;
1499         else
1500                 cmd = F_DUP2FD;
1501
1502         newfd = args->newfd;
1503         return (kern_fcntl(td, args->oldfd, cmd, newfd));
1504 }
1505
1506 int
1507 linux_fallocate(struct thread *td, struct linux_fallocate_args *args)
1508 {
1509
1510         /*
1511          * We emulate only posix_fallocate system call for which
1512          * mode should be 0.
1513          */
1514         if (args->mode != 0)
1515                 return (ENOSYS);
1516
1517         return (kern_posix_fallocate(td, args->fd, args->offset,
1518             args->len));
1519 }