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