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