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