s/firmware.h/fbsd_firmware.h/
[dragonfly.git] / sys / emulation / 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 withough 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  * $FreeBSD: src/sys/compat/linux/linux_file.c,v 1.41.2.6 2003/01/06 09:19:43 fjoe Exp $
29  * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.39 2008/09/28 05:08:16 dillon Exp $
30  */
31
32 #include "opt_compat.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/dirent.h>
38 #include <sys/fcntl.h>
39 #include <sys/file.h>
40 #include <sys/stat.h>
41 #include <sys/filedesc.h>
42 #include <sys/kern_syscall.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mount.h>
46 #include <sys/nlookup.h>
47 #include <sys/proc.h>
48 #include <sys/sysproto.h>
49 #include <sys/tty.h>
50 #include <sys/vnode.h>
51
52 #include <vfs/ufs/quota.h>
53 #include <vfs/ufs/ufsmount.h>
54
55 #include <sys/file2.h>
56 #include <sys/mplock2.h>
57
58 #include <arch_linux/linux.h>
59 #include <arch_linux/linux_proto.h>
60 #include "linux_util.h"
61
62 /*
63  * MPALMOSTSAFE
64  */
65 int
66 sys_linux_creat(struct linux_creat_args *args)
67 {
68         struct nlookupdata nd;
69         char *path;
70         int error;
71
72         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
73         if (error)
74                 return (error);
75 #ifdef DEBUG
76         if (ldebug(creat))
77                 kprintf(ARGS(creat, "%s, %d"), path, args->mode);
78 #endif
79         get_mplock();
80         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
81         if (error == 0) {
82                 error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC,
83                                   args->mode, &args->sysmsg_iresult);
84         }
85         rel_mplock();
86         linux_free_path(&path);
87         return(error);
88 }
89
90 /*
91  * MPALMOSTSAFE
92  */
93 int
94 sys_linux_open(struct linux_open_args *args)
95 {
96         struct thread *td = curthread;
97         struct proc *p = td->td_proc;
98         struct nlookupdata nd;
99         char *path;
100         int error, flags;
101
102         if (args->flags & LINUX_O_CREAT) {
103                 error = linux_copyin_path(args->path, &path,
104                     LINUX_PATH_CREATE);
105         } else {
106                 error = linux_copyin_path(args->path, &path,
107                     LINUX_PATH_EXISTS);
108         }
109         if (error)
110                 return (error);
111
112 #ifdef DEBUG
113         if (ldebug(open))
114                 kprintf(ARGS(open, "%s, 0x%x, 0x%x"), path, args->flags,
115                     args->mode);
116 #endif
117         flags = 0;
118         if (args->flags & LINUX_O_RDONLY)
119                 flags |= O_RDONLY;
120         if (args->flags & LINUX_O_WRONLY)
121                 flags |= O_WRONLY;
122         if (args->flags & LINUX_O_RDWR)
123                 flags |= O_RDWR;
124         if (args->flags & LINUX_O_NDELAY)
125                 flags |= O_NONBLOCK;
126         if (args->flags & LINUX_O_APPEND)
127                 flags |= O_APPEND;
128         if (args->flags & LINUX_O_SYNC)
129                 flags |= O_FSYNC;
130         if (args->flags & LINUX_O_NONBLOCK)
131                 flags |= O_NONBLOCK;
132         if (args->flags & LINUX_FASYNC)
133                 flags |= O_ASYNC;
134         if (args->flags & LINUX_O_CREAT)
135                 flags |= O_CREAT;
136         if (args->flags & LINUX_O_TRUNC)
137                 flags |= O_TRUNC;
138         if (args->flags & LINUX_O_EXCL)
139                 flags |= O_EXCL;
140         if (args->flags & LINUX_O_NOCTTY)
141                 flags |= O_NOCTTY;
142         get_mplock();
143         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
144         if (error == 0) {
145                 error = kern_open(&nd, flags,
146                                   args->mode, &args->sysmsg_iresult);
147         }
148         nlookup_done(&nd);
149
150         if (error == 0 && !(flags & O_NOCTTY) && 
151                 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
152                 struct file *fp;
153
154                 fp = holdfp(p->p_fd, args->sysmsg_iresult, -1);
155                 if (fp) {
156                         if (fp->f_type == DTYPE_VNODE) {
157                                 fo_ioctl(fp, TIOCSCTTY, NULL,
158                                          td->td_ucred, NULL);
159                         }
160                         fdrop(fp);
161                 }
162         }
163         rel_mplock();
164 #ifdef DEBUG
165         if (ldebug(open))
166                 kprintf(LMSG("open returns error %d"), error);
167 #endif
168         linux_free_path(&path);
169         return error;
170 }
171
172 int
173 sys_linux_openat(struct linux_openat_args *args)
174 {
175         struct thread *td = curthread;
176         struct proc *p = td->td_proc;
177         struct nlookupdata nd;
178         struct file *fp;
179         char *path;
180         int error, flags, dfd;
181
182         if (args->flags & LINUX_O_CREAT) {
183                 error = linux_copyin_path(args->path, &path,
184                     LINUX_PATH_CREATE);
185         } else {
186                 error = linux_copyin_path(args->path, &path,
187                     LINUX_PATH_EXISTS);
188         }
189         if (error)
190                 return (error);
191
192 #ifdef DEBUG
193         if (ldebug(open))
194                 kprintf(ARGS(open, "%s, 0x%x, 0x%x"), path, args->flags,
195                     args->mode);
196 #endif
197         flags = 0;
198         if (args->flags & LINUX_O_RDONLY)
199                 flags |= O_RDONLY;
200         if (args->flags & LINUX_O_WRONLY)
201                 flags |= O_WRONLY;
202         if (args->flags & LINUX_O_RDWR)
203                 flags |= O_RDWR;
204         if (args->flags & LINUX_O_NDELAY)
205                 flags |= O_NONBLOCK;
206         if (args->flags & LINUX_O_APPEND)
207                 flags |= O_APPEND;
208         if (args->flags & LINUX_O_SYNC)
209                 flags |= O_FSYNC;
210         if (args->flags & LINUX_O_NONBLOCK)
211                 flags |= O_NONBLOCK;
212         if (args->flags & LINUX_FASYNC)
213                 flags |= O_ASYNC;
214         if (args->flags & LINUX_O_CREAT)
215                 flags |= O_CREAT;
216         if (args->flags & LINUX_O_TRUNC)
217                 flags |= O_TRUNC;
218         if (args->flags & LINUX_O_EXCL)
219                 flags |= O_EXCL;
220         if (args->flags & LINUX_O_NOCTTY)
221                 flags |= O_NOCTTY;
222
223         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
224         get_mplock();
225         error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, NLC_FOLLOW);
226         if (error == 0) {
227                 error = kern_open(&nd, flags,
228                                   args->mode, &args->sysmsg_iresult);
229         }
230         nlookup_done_at(&nd, fp);
231
232         if (error == 0 && !(flags & O_NOCTTY) && 
233                 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
234                 struct file *fp;
235
236                 fp = holdfp(p->p_fd, args->sysmsg_iresult, -1);
237                 if (fp) {
238                         if (fp->f_type == DTYPE_VNODE) {
239                                 fo_ioctl(fp, TIOCSCTTY, NULL,
240                                          td->td_ucred, NULL);
241                         }
242                         fdrop(fp);
243                 }
244         }
245         rel_mplock();
246 #ifdef DEBUG
247         if (ldebug(open))
248                 kprintf(LMSG("open returns error %d"), error);
249 #endif
250         linux_free_path(&path);
251         return error;
252 }
253
254 /*
255  * MPSAFE
256  */
257 int
258 sys_linux_lseek(struct linux_lseek_args *args)
259 {
260         int error;
261
262 #ifdef DEBUG
263         if (ldebug(lseek))
264                 kprintf(ARGS(lseek, "%d, %ld, %d"),
265                     args->fdes, (long)args->off, args->whence);
266 #endif
267         error = kern_lseek(args->fdes, args->off, args->whence,
268                            &args->sysmsg_offset);
269
270         return error;
271 }
272
273 /*
274  * MPSAFE
275  */
276 int
277 sys_linux_llseek(struct linux_llseek_args *args)
278 {
279         int error;
280         off_t off, res;
281
282 #ifdef DEBUG
283         if (ldebug(llseek))
284                 kprintf(ARGS(llseek, "%d, %d:%d, %d"),
285                     args->fd, args->ohigh, args->olow, args->whence);
286 #endif
287         off = (args->olow) | (((off_t) args->ohigh) << 32);
288
289         error = kern_lseek(args->fd, off, args->whence, &res);
290
291         if (error == 0)
292                 error = copyout(&res, args->res, sizeof(res));
293         return (error);
294 }
295
296 /*
297  * MPSAFE
298  */
299 int
300 sys_linux_readdir(struct linux_readdir_args *args)
301 {
302         struct linux_getdents_args lda;
303         int error;
304
305         lda.fd = args->fd;
306         lda.dent = args->dent;
307         lda.count = -1;
308         lda.sysmsg_iresult = 0;
309         error = sys_linux_getdents(&lda);
310         args->sysmsg_iresult = lda.sysmsg_iresult;
311         return(error);
312 }
313
314 /*
315  * Note that linux_getdents(2) and linux_getdents64(2) have the same
316  * arguments. They only differ in the definition of struct dirent they
317  * operate on. We use this to common the code, with the exception of
318  * accessing struct dirent. Note that linux_readdir(2) is implemented
319  * by means of linux_getdents(2). In this case we never operate on
320  * struct dirent64 and thus don't need to handle it...
321  */
322
323 struct l_dirent {
324         l_long          d_ino;
325         l_off_t         d_off;
326         l_ushort        d_reclen;
327         char            d_name[LINUX_NAME_MAX + 1];
328 };
329
330 struct l_dirent64 {
331         uint64_t        d_ino;
332         int64_t         d_off;
333         l_ushort        d_reclen;
334         u_char          d_type;
335         char            d_name[LINUX_NAME_MAX + 1];
336 };
337
338 #define LINUX_RECLEN(de,namlen) \
339     ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
340
341 #define LINUX_DIRBLKSIZ         512
342
343 /*
344  * MPALMOSTSAFE
345  */
346 static int
347 getdents_common(struct linux_getdents64_args *args, int is64bit)
348 {
349         struct thread *td = curthread;
350         struct proc *p = td->td_proc;
351         struct dirent *bdp;
352         struct vnode *vp;
353         caddr_t inp, buf;               /* BSD-format */
354         int reclen;                     /* BSD-format */
355         size_t len;
356         caddr_t outp;                   /* Linux-format */
357         int linuxreclen = 0;            /* Linux-format */
358         size_t resid;
359         struct file *fp;
360         struct uio auio;
361         struct iovec aiov;
362         struct vattr va;
363         off_t off;
364         struct l_dirent linux_dirent;
365         struct l_dirent64 linux_dirent64;
366         int error, eofflag, justone;
367         size_t buflen, nbytes;
368         off_t *cookies = NULL, *cookiep;
369         int ncookies;
370
371         if ((error = holdvnode(p->p_fd, args->fd, &fp)) != 0)
372                 return (error);
373
374         get_mplock();
375         if ((fp->f_flag & FREAD) == 0) {
376                 error = EBADF;
377                 goto done;
378         }
379
380         vp = (struct vnode *) fp->f_data;
381         if (vp->v_type != VDIR) {
382                 error = EINVAL;
383                 goto done;
384         }
385
386         if ((error = VOP_GETATTR(vp, &va)) != 0)
387                 goto done;
388
389         nbytes = args->count;
390         if (nbytes == (size_t)-1) {
391                 /* readdir(2) case. Always struct dirent. */
392                 if (is64bit) {
393                         error = EINVAL;
394                         goto done;
395                 }
396                 nbytes = sizeof(linux_dirent);
397                 justone = 1;
398         } else {
399                 justone = 0;
400         }
401         if ((size_t)nbytes < 0)
402                 nbytes = 0;
403
404         off = fp->f_offset;
405
406         buflen = max(LINUX_DIRBLKSIZ, nbytes);
407         buflen = min(buflen, MAXBSIZE);
408         buf = kmalloc(buflen, M_TEMP, M_WAITOK);
409
410 again:
411         aiov.iov_base = buf;
412         aiov.iov_len = buflen;
413         auio.uio_iov = &aiov;
414         auio.uio_iovcnt = 1;
415         auio.uio_rw = UIO_READ;
416         auio.uio_segflg = UIO_SYSSPACE;
417         auio.uio_td = td;
418         auio.uio_resid = buflen;
419         auio.uio_offset = off;
420
421         if (cookies) {
422                 kfree(cookies, M_TEMP);
423                 cookies = NULL;
424         }
425
426         eofflag = 0;
427         ncookies = 0;
428         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
429                  &cookies)))
430                 goto out;
431
432         inp = buf;
433         outp = (caddr_t)args->dirent;
434         resid = nbytes;
435         if (auio.uio_resid >= buflen)
436                 goto eof;
437         len = buflen - auio.uio_resid;
438         cookiep = cookies;
439
440         if (cookies) {
441                 /*
442                  * When using cookies, the vfs has the option of reading from
443                  * a different offset than that supplied (UFS truncates the
444                  * offset to a block boundary to make sure that it never reads
445                  * partway through a directory entry, even if the directory
446                  * has been compacted).
447                  */
448                 while (len > 0 && ncookies > 0 && *cookiep < off) {
449                         bdp = (struct dirent *) inp;
450                         len -= _DIRENT_DIRSIZ(bdp);
451                         inp += _DIRENT_DIRSIZ(bdp);
452                         cookiep++;
453                         ncookies--;
454                 }
455         }
456
457         while (len > 0) {
458                 if (cookiep && ncookies == 0)
459                         break;
460                 bdp = (struct dirent *) inp;
461                 reclen = _DIRENT_DIRSIZ(bdp);
462                 if (reclen & 3) {
463                         error = EFAULT;
464                         goto out;
465                 }
466
467                 if (bdp->d_ino == 0) {
468                         inp += reclen;
469                         if (cookiep) {
470                                 off = *cookiep++;
471                                 ++off;
472                                 ncookies--;
473                         } else {
474                                 off += reclen;
475                         }
476                         len -= reclen;
477                         continue;
478                 }
479
480                 linuxreclen = (is64bit)
481                     ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
482                     : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
483
484                 if (reclen > len || resid < linuxreclen) {
485                         outp++;
486                         break;
487                 }
488
489                 bzero(&linux_dirent, sizeof(linux_dirent));
490                 bzero(&linux_dirent64, sizeof(linux_dirent64));
491                 if (justone) {
492                         /* readdir(2) case. */
493                         linux_dirent.d_ino = (l_long)INO64TO32(bdp->d_ino);
494                         linux_dirent.d_off = (l_off_t)linuxreclen;
495                         linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
496                         strcpy(linux_dirent.d_name, bdp->d_name);
497                         error = copyout(&linux_dirent, outp, linuxreclen);
498                 } else {
499                         if (is64bit) {
500                                 linux_dirent64.d_ino = INO64TO32(bdp->d_ino);
501                                 linux_dirent64.d_off = (cookiep)
502                                     ? (l_off_t)*cookiep
503                                     : (l_off_t)(off + reclen);
504                                 linux_dirent64.d_reclen =
505                                     (l_ushort)linuxreclen;
506                                 linux_dirent64.d_type = bdp->d_type;
507                                 strcpy(linux_dirent64.d_name, bdp->d_name);
508                                 error = copyout(&linux_dirent64, outp,
509                                     linuxreclen);
510                         } else {
511                                 linux_dirent.d_ino = INO64TO32(bdp->d_ino);
512                                 linux_dirent.d_off = (cookiep)
513                                     ? (l_off_t)*cookiep
514                                     : (l_off_t)(off + reclen);
515                                 linux_dirent.d_reclen = (l_ushort)linuxreclen;
516                                 strcpy(linux_dirent.d_name, bdp->d_name);
517                                 error = copyout(&linux_dirent, outp,
518                                     linuxreclen);
519                         }
520                 }
521                 if (error)
522                         goto out;
523
524                 inp += reclen;
525                 if (cookiep) {
526                         off = *cookiep++;
527                         ++off;
528                         ncookies--;
529                 } else {
530                         off += reclen;
531                 }
532
533                 outp += linuxreclen;
534                 resid -= linuxreclen;
535                 len -= reclen;
536                 if (justone)
537                         break;
538         }
539
540         if (outp == (caddr_t)args->dirent && eofflag == 0)
541                 goto again;
542
543         fp->f_offset = off;
544         if (justone)
545                 nbytes = resid + linuxreclen;
546
547 eof:
548         args->sysmsg_iresult = (int)(nbytes - resid);
549
550 out:
551         if (cookies)
552                 kfree(cookies, M_TEMP);
553
554         kfree(buf, M_TEMP);
555 done:
556         rel_mplock();
557         fdrop(fp);
558         return (error);
559 }
560
561 /*
562  * MPSAFE
563  */
564 int
565 sys_linux_getdents(struct linux_getdents_args *args)
566 {
567 #ifdef DEBUG
568         if (ldebug(getdents))
569                 kprintf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
570 #endif
571         return (getdents_common((struct linux_getdents64_args*)args, 0));
572 }
573
574 /*
575  * MPSAFE
576  */
577 int
578 sys_linux_getdents64(struct linux_getdents64_args *args)
579 {
580 #ifdef DEBUG
581         if (ldebug(getdents64))
582                 kprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
583 #endif
584         return (getdents_common(args, 1));
585 }
586
587 /*
588  * These exist mainly for hooks for doing /compat/linux translation.
589  *
590  * MPALMOSTSAFE
591  */
592 int
593 sys_linux_access(struct linux_access_args *args)
594 {
595         struct nlookupdata nd;
596         char *path;
597         int error;
598
599         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
600         if (error)
601                 return (error);
602 #ifdef DEBUG
603         if (ldebug(access))
604                 kprintf(ARGS(access, "%s, %d"), path, args->flags);
605 #endif
606         get_mplock();
607         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
608         if (error == 0)
609                 error = kern_access(&nd, args->flags, 0);
610         nlookup_done(&nd);
611         rel_mplock();
612         linux_free_path(&path);
613         return(error);
614 }
615
616 /*
617  * MPALMOSTSAFE
618  */
619 int
620 sys_linux_unlink(struct linux_unlink_args *args)
621 {
622         struct nlookupdata nd;
623         char *path;
624         int error;
625
626         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
627         if (error)
628                 return (error);
629 #ifdef DEBUG
630         if (ldebug(unlink))
631                 kprintf(ARGS(unlink, "%s"), path);
632 #endif
633         get_mplock();
634         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
635         if (error == 0)
636                 error = kern_unlink(&nd);
637         nlookup_done(&nd);
638         rel_mplock();
639         linux_free_path(&path);
640         return(error);
641 }
642
643 int
644 sys_linux_unlinkat(struct linux_unlinkat_args *args)
645 {
646         struct nlookupdata nd;
647         struct file *fp;
648         char *path;
649         int dfd, error;
650
651         if (args->flag & ~LINUX_AT_REMOVEDIR)
652                 return (EINVAL);
653
654         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
655         if (error) {
656                 kprintf("linux_copyin_path says error = %d\n", error);
657                 return (error);
658         }
659 #ifdef DEBUG
660         if (ldebug(unlink))
661                 kprintf(ARGS(unlink, "%s"), path);
662 #endif
663
664         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
665         get_mplock();
666         error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
667         if (error == 0) {
668                 if (args->flag & LINUX_AT_REMOVEDIR)
669                         error = kern_rmdir(&nd);
670                 else
671                         error = kern_unlink(&nd);
672         }
673         nlookup_done_at(&nd, fp);
674         rel_mplock();
675         linux_free_path(&path);
676         return(error);
677 }
678
679 /*
680  * MPALMOSTSAFE
681  */
682 int
683 sys_linux_chdir(struct linux_chdir_args *args)
684 {
685         struct nlookupdata nd;
686         char *path;
687         int error;
688
689         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
690         if (error)
691                 return (error);
692 #ifdef DEBUG
693         if (ldebug(chdir))
694                 kprintf(ARGS(chdir, "%s"), path);
695 #endif
696         get_mplock();
697         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
698         if (error == 0) {
699                 error = kern_chdir(&nd);
700                 nlookup_done(&nd);
701         }
702         rel_mplock();
703         linux_free_path(&path);
704         return(error);
705 }
706
707 /*
708  * MPALMOSTSAFE
709  */
710 int
711 sys_linux_chmod(struct linux_chmod_args *args)
712 {
713         struct nlookupdata nd;
714         char *path;
715         int error;
716
717         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
718         if (error)
719                 return (error);
720 #ifdef DEBUG
721         if (ldebug(chmod))
722                 kprintf(ARGS(chmod, "%s, %d"), path, args->mode);
723 #endif
724         get_mplock();
725         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
726         if (error == 0)
727                 error = kern_chmod(&nd, args->mode);
728         nlookup_done(&nd);
729         rel_mplock();
730         linux_free_path(&path);
731         return(error);
732 }
733
734 /*
735  * MPALMOSTSAFE
736  */
737 int
738 sys_linux_mkdir(struct linux_mkdir_args *args)
739 {
740         struct nlookupdata nd;
741         char *path;
742         int error;
743
744         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
745         if (error)
746                 return (error);
747 #ifdef DEBUG
748         if (ldebug(mkdir))
749                 kprintf(ARGS(mkdir, "%s, %d"), path, args->mode);
750 #endif
751         get_mplock();
752         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
753         if (error == 0)
754                 error = kern_mkdir(&nd, args->mode);
755         nlookup_done(&nd);
756         rel_mplock();
757
758         linux_free_path(&path);
759         return(error);
760 }
761
762 int
763 sys_linux_mkdirat(struct linux_mkdirat_args *args)
764 {
765         struct nlookupdata nd;
766         struct file *fp;
767         char *path;
768         int dfd, error;
769
770         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
771         if (error)
772                 return (error);
773 #ifdef DEBUG
774         if (ldebug(mkdir))
775                 kprintf(ARGS(mkdir, "%s, %d"), path, args->mode);
776 #endif
777         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
778         get_mplock();
779         error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
780         if (error == 0)
781                 error = kern_mkdir(&nd, args->mode);
782         nlookup_done_at(&nd, fp);
783         rel_mplock();
784
785         linux_free_path(&path);
786         return(error);
787 }
788
789 /*
790  * MPALMOSTSAFE
791  */
792 int
793 sys_linux_rmdir(struct linux_rmdir_args *args)
794 {
795         struct nlookupdata nd;
796         char *path;
797         int error;
798
799         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
800         if (error)
801                 return (error);
802 #ifdef DEBUG
803         if (ldebug(rmdir))
804                 kprintf(ARGS(rmdir, "%s"), path);
805 #endif
806         get_mplock();
807         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
808         if (error == 0)
809                 error = kern_rmdir(&nd);
810         nlookup_done(&nd);
811         rel_mplock();
812         linux_free_path(&path);
813         return(error);
814 }
815
816 /*
817  * MPALMOSTSAFE
818  */
819 int
820 sys_linux_rename(struct linux_rename_args *args)
821 {
822         struct nlookupdata fromnd, tond;
823         char *from, *to;
824         int error;
825
826         error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
827         if (error)
828                 return (error);
829         error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
830         if (error) {
831                 linux_free_path(&from);
832                 return (error);
833         }
834 #ifdef DEBUG
835         if (ldebug(rename))
836                 kprintf(ARGS(rename, "%s, %s"), from, to);
837 #endif
838         get_mplock();
839         error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0);
840         if (error == 0) {
841                 error = nlookup_init(&tond, to, UIO_SYSSPACE, 0);
842                 if (error == 0)
843                         error = kern_rename(&fromnd, &tond);
844                 nlookup_done(&tond);
845         }
846         nlookup_done(&fromnd);
847         rel_mplock();
848         linux_free_path(&from);
849         linux_free_path(&to);
850         return(error);
851 }
852
853 int
854 sys_linux_renameat(struct linux_renameat_args *args)
855 {
856         struct nlookupdata fromnd, tond;
857         struct file *fp, *fp2;
858         char *from, *to;
859         int olddfd, newdfd,error;
860
861         error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
862         if (error)
863                 return (error);
864         error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
865         if (error) {
866                 linux_free_path(&from);
867                 return (error);
868         }
869 #ifdef DEBUG
870         if (ldebug(rename))
871                 kprintf(ARGS(rename, "%s, %s"), from, to);
872 #endif
873         olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
874         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
875         get_mplock();
876         error = nlookup_init_at(&fromnd, &fp, olddfd, from, UIO_SYSSPACE, 0);
877         if (error == 0) {
878                 error = nlookup_init_at(&tond, &fp2, newdfd, to, UIO_SYSSPACE, 0);
879                 if (error == 0)
880                         error = kern_rename(&fromnd, &tond);
881                 nlookup_done_at(&tond, fp2);
882         }
883         nlookup_done_at(&fromnd, fp);
884         rel_mplock();
885         linux_free_path(&from);
886         linux_free_path(&to);
887         return(error);
888 }
889
890 /*
891  * MPALMOSTSAFE
892  */
893 int
894 sys_linux_symlink(struct linux_symlink_args *args)
895 {
896         struct thread *td = curthread;
897         struct nlookupdata nd;
898         char *path, *link;
899         int error;
900         int mode;
901
902         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
903         if (error)
904                 return (error);
905         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
906         if (error) {
907                 linux_free_path(&path);
908                 return (error);
909         }
910 #ifdef DEBUG
911         if (ldebug(symlink))
912                 kprintf(ARGS(symlink, "%s, %s"), path, link);
913 #endif
914         get_mplock();
915         error = nlookup_init(&nd, link, UIO_SYSSPACE, 0);
916         if (error == 0) {
917                 mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
918                 error = kern_symlink(&nd, path, mode);
919         }
920         nlookup_done(&nd);
921         rel_mplock();
922         linux_free_path(&path);
923         linux_free_path(&link);
924         return(error);
925 }
926
927 int
928 sys_linux_symlinkat(struct linux_symlinkat_args *args)
929 {
930         struct thread *td = curthread;
931         struct nlookupdata nd;
932         struct file *fp;
933         char *path, *link;
934         int error;
935         int newdfd, mode;
936
937         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
938         if (error)
939                 return (error);
940         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
941         if (error) {
942                 linux_free_path(&path);
943                 return (error);
944         }
945 #ifdef DEBUG
946         if (ldebug(symlink))
947                 kprintf(ARGS(symlink, "%s, %s"), path, link);
948 #endif
949         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
950         get_mplock();
951         error = nlookup_init_at(&nd, &fp, newdfd, link, UIO_SYSSPACE, 0);
952         if (error == 0) {
953                 mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
954                 error = kern_symlink(&nd, path, mode);
955         }
956         nlookup_done_at(&nd, fp);
957         rel_mplock();
958         linux_free_path(&path);
959         linux_free_path(&link);
960         return(error);
961 }
962
963 /*
964  * MPALMOSTSAFE
965  */
966 int
967 sys_linux_readlink(struct linux_readlink_args *args)
968 {
969         struct nlookupdata nd;
970         char *path;
971         int error;
972
973         error = linux_copyin_path(args->name, &path, LINUX_PATH_EXISTS);
974         if (error)
975                 return (error);
976 #ifdef DEBUG
977         if (ldebug(readlink))
978                 kprintf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
979                     args->count);
980 #endif
981         get_mplock();
982         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
983         if (error == 0) {
984                 error = kern_readlink(&nd, args->buf, args->count,
985                                       &args->sysmsg_iresult);
986         }
987         nlookup_done(&nd);
988         rel_mplock();
989         linux_free_path(&path);
990         return(error);
991 }
992
993 int
994 sys_linux_readlinkat(struct linux_readlinkat_args *args)
995 {
996         struct nlookupdata nd;
997         struct file *fp;
998         char *path;
999         int dfd, error;
1000
1001         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1002         if (error)
1003                 return (error);
1004 #ifdef DEBUG
1005         if (ldebug(readlink))
1006                 kprintf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
1007                     args->count);
1008 #endif
1009         dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
1010         get_mplock();
1011         error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
1012         if (error == 0) {
1013                 error = kern_readlink(&nd, args->buf, args->count,
1014                                       &args->sysmsg_iresult);
1015         }
1016         nlookup_done_at(&nd, fp);
1017         rel_mplock();
1018         linux_free_path(&path);
1019         return(error);
1020 }
1021
1022 /*
1023  * MPALMOSTSAFE
1024  */
1025 int
1026 sys_linux_truncate(struct linux_truncate_args *args)
1027 {
1028         struct nlookupdata nd;
1029         char *path;
1030         int error;
1031
1032         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1033         if (error)
1034                 return (error);
1035 #ifdef DEBUG
1036         if (ldebug(truncate))
1037                 kprintf(ARGS(truncate, "%s, %ld"), path,
1038                     (long)args->length);
1039 #endif
1040         get_mplock();
1041         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1042         if (error == 0)
1043                 error = kern_truncate(&nd, args->length);
1044         nlookup_done(&nd);
1045         rel_mplock();
1046         linux_free_path(&path);
1047         return(error);
1048 }
1049
1050 /*
1051  * MPALMOSTSAFE
1052  */
1053 int
1054 sys_linux_truncate64(struct linux_truncate64_args *args)
1055 {
1056         struct nlookupdata nd;
1057         char *path;
1058         int error;
1059
1060         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1061         if (error)
1062                 return (error);
1063 #ifdef DEBUG
1064         if (ldebug(truncate64))
1065                 kprintf(ARGS(truncate64, "%s, %lld"), path,
1066                     (off_t)args->length);
1067 #endif
1068         get_mplock();
1069         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1070         if (error == 0)
1071                 error = kern_truncate(&nd, args->length);
1072         nlookup_done(&nd);
1073         rel_mplock();
1074         linux_free_path(&path);
1075         return error;
1076 }
1077
1078 /*
1079  * MPALMOSTSAFE
1080  */
1081 int
1082 sys_linux_ftruncate(struct linux_ftruncate_args *args)
1083 {
1084         int error;
1085
1086 #ifdef DEBUG
1087         if (ldebug(ftruncate))
1088                 kprintf(ARGS(ftruncate, "%d, %ld"), args->fd,
1089                     (long)args->length);
1090 #endif
1091         get_mplock();
1092         error = kern_ftruncate(args->fd, args->length);
1093         rel_mplock();
1094
1095         return error;
1096 }
1097
1098 /*
1099  * MPALMOSTSAFE
1100  */
1101 int
1102 sys_linux_ftruncate64(struct linux_ftruncate64_args *args)
1103 {
1104         int error;
1105
1106 #ifdef DEBUG
1107         if (ldebug(ftruncate))
1108                 kprintf(ARGS(ftruncate64, "%d, %lld"), args->fd,
1109                     (off_t)args->length);
1110 #endif
1111         get_mplock();
1112         error = kern_ftruncate(args->fd, args->length);
1113         rel_mplock();
1114
1115         return error;
1116 }
1117
1118 /*
1119  * MPALMOSTSAFE
1120  */
1121 int
1122 sys_linux_link(struct linux_link_args *args)
1123 {
1124         struct nlookupdata nd, linknd;
1125         char *path, *link;
1126         int error;
1127
1128         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1129         if (error)
1130                 return (error);
1131         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
1132         if (error) {
1133                 linux_free_path(&path);
1134                 return (error);
1135         }
1136 #ifdef DEBUG
1137         if (ldebug(link))
1138                 kprintf(ARGS(link, "%s, %s"), path, link);
1139 #endif
1140         get_mplock();
1141         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1142         if (error == 0) {
1143                 error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0);
1144                 if (error == 0)
1145                         error = kern_link(&nd, &linknd);
1146                 nlookup_done(&linknd);
1147         }
1148         nlookup_done(&nd);
1149         rel_mplock();
1150         linux_free_path(&path);
1151         linux_free_path(&link);
1152         return(error);
1153 }
1154
1155 int
1156 sys_linux_linkat(struct linux_linkat_args *args)
1157 {
1158         struct nlookupdata nd, linknd;
1159         struct file *fp, *fp2;
1160         char *path, *link;
1161         int olddfd, newdfd, error;
1162
1163         if (args->flags != 0)
1164                 return (EINVAL);
1165
1166         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1167         if (error)
1168                 return (error);
1169         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
1170         if (error) {
1171                 linux_free_path(&path);
1172                 return (error);
1173         }
1174 #ifdef DEBUG
1175         if (ldebug(link))
1176                 kprintf(ARGS(link, "%s, %s"), path, link);
1177 #endif
1178         olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
1179         newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
1180         get_mplock();
1181         error = nlookup_init_at(&nd, &fp, olddfd, path, UIO_SYSSPACE, NLC_FOLLOW);
1182         if (error == 0) {
1183                 error = nlookup_init_at(&linknd, &fp2, newdfd, link, UIO_SYSSPACE, 0);
1184                 if (error == 0)
1185                         error = kern_link(&nd, &linknd);
1186                 nlookup_done_at(&linknd, fp2);
1187         }
1188         nlookup_done_at(&nd, fp);
1189         rel_mplock();
1190         linux_free_path(&path);
1191         linux_free_path(&link);
1192         return(error);
1193 }
1194
1195 /*
1196  * MPSAFE
1197  */
1198 int
1199 sys_linux_fdatasync(struct linux_fdatasync_args *uap)
1200 {
1201         struct fsync_args bsd;
1202         int error;
1203
1204         bsd.fd = uap->fd;
1205         bsd.sysmsg_iresult = 0;
1206
1207         error = sys_fsync(&bsd);
1208         uap->sysmsg_iresult = bsd.sysmsg_iresult;
1209         return(error);
1210 }
1211
1212 /*
1213  * MPSAFE
1214  */
1215 int
1216 sys_linux_pread(struct linux_pread_args *uap)
1217 {
1218         struct thread *td = curthread;
1219         struct uio auio;
1220         struct iovec aiov;
1221         int error;
1222
1223         aiov.iov_base = uap->buf;
1224         aiov.iov_len = uap->nbyte;
1225         auio.uio_iov = &aiov;
1226         auio.uio_iovcnt = 1;
1227         auio.uio_offset = uap->offset;
1228         auio.uio_resid = uap->nbyte;
1229         auio.uio_rw = UIO_READ;
1230         auio.uio_segflg = UIO_USERSPACE;
1231         auio.uio_td = td;
1232
1233         if ((ssize_t)auio.uio_resid < 0) {
1234                 error = EINVAL;
1235         } else {
1236                 error = kern_preadv(uap->fd, &auio, O_FOFFSET,
1237                                     &uap->sysmsg_szresult);
1238         }
1239         return(error);
1240 }
1241
1242 /*
1243  * MPSAFE
1244  */
1245 int
1246 sys_linux_pwrite(struct linux_pwrite_args *uap)
1247 {
1248         struct thread *td = curthread;
1249         struct uio auio;
1250         struct iovec aiov;
1251         int error;
1252
1253         aiov.iov_base = uap->buf;
1254         aiov.iov_len = uap->nbyte;
1255         auio.uio_iov = &aiov;
1256         auio.uio_iovcnt = 1;
1257         auio.uio_offset = uap->offset;
1258         auio.uio_resid = uap->nbyte;
1259         auio.uio_rw = UIO_WRITE;
1260         auio.uio_segflg = UIO_USERSPACE;
1261         auio.uio_td = td;
1262
1263         if ((ssize_t)auio.uio_resid < 0) {
1264                 error = EINVAL;
1265         } else {
1266                 error = kern_pwritev(uap->fd, &auio, O_FOFFSET,
1267                                      &uap->sysmsg_szresult);
1268         }
1269         return(error);
1270 }
1271
1272 /*
1273  * MPSAFE
1274  */
1275 int
1276 sys_linux_oldumount(struct linux_oldumount_args *args)
1277 {
1278         struct linux_umount_args args2;
1279         int error;
1280
1281         args2.path = args->path;
1282         args2.flags = 0;
1283         args2.sysmsg_iresult = 0;
1284         error = sys_linux_umount(&args2);
1285         args->sysmsg_iresult = args2.sysmsg_iresult;
1286         return(error);
1287 }
1288
1289 /*
1290  * MPSAFE
1291  */
1292 int
1293 sys_linux_umount(struct linux_umount_args *args)
1294 {
1295         struct unmount_args bsd;
1296         int error;
1297
1298         bsd.path = args->path;
1299         bsd.flags = args->flags;        /* XXX correct? */
1300         bsd.sysmsg_iresult = 0;
1301
1302         error = sys_unmount(&bsd);
1303         args->sysmsg_iresult = bsd.sysmsg_iresult;
1304         return(error);
1305 }
1306
1307 /*
1308  * fcntl family of syscalls
1309  */
1310 struct l_flock {
1311         l_short         l_type;
1312         l_short         l_whence;
1313         l_off_t         l_start;
1314         l_off_t         l_len;
1315         l_pid_t         l_pid;
1316 };
1317
1318 /*
1319  * MPSAFE
1320  */
1321 static void
1322 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1323 {
1324         switch (linux_flock->l_type) {
1325         case LINUX_F_RDLCK:
1326                 bsd_flock->l_type = F_RDLCK;
1327                 break;
1328         case LINUX_F_WRLCK:
1329                 bsd_flock->l_type = F_WRLCK;
1330                 break;
1331         case LINUX_F_UNLCK:
1332                 bsd_flock->l_type = F_UNLCK;
1333                 break;
1334         default:
1335                 bsd_flock->l_type = -1;
1336                 break;
1337         }
1338         bsd_flock->l_whence = linux_flock->l_whence;
1339         bsd_flock->l_start = (off_t)linux_flock->l_start;
1340         bsd_flock->l_len = (off_t)linux_flock->l_len;
1341         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1342 }
1343
1344 /*
1345  * MPSAFE
1346  */
1347 static void
1348 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1349 {
1350         switch (bsd_flock->l_type) {
1351         case F_RDLCK:
1352                 linux_flock->l_type = LINUX_F_RDLCK;
1353                 break;
1354         case F_WRLCK:
1355                 linux_flock->l_type = LINUX_F_WRLCK;
1356                 break;
1357         case F_UNLCK:
1358                 linux_flock->l_type = LINUX_F_UNLCK;
1359                 break;
1360         }
1361         linux_flock->l_whence = bsd_flock->l_whence;
1362         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1363         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1364         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1365 }
1366
1367 #if defined(__i386__)
1368 struct l_flock64 {
1369         l_short         l_type;
1370         l_short         l_whence;
1371         l_loff_t        l_start;
1372         l_loff_t        l_len;
1373         l_pid_t         l_pid;
1374 };
1375
1376 /*
1377  * MPSAFE
1378  */
1379 static void
1380 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1381 {
1382         switch (linux_flock->l_type) {
1383         case LINUX_F_RDLCK:
1384                 bsd_flock->l_type = F_RDLCK;
1385                 break;
1386         case LINUX_F_WRLCK:
1387                 bsd_flock->l_type = F_WRLCK;
1388                 break;
1389         case LINUX_F_UNLCK:
1390                 bsd_flock->l_type = F_UNLCK;
1391                 break;
1392         default:
1393                 bsd_flock->l_type = -1;
1394                 break;
1395         }
1396         bsd_flock->l_whence = linux_flock->l_whence;
1397         bsd_flock->l_start = (off_t)linux_flock->l_start;
1398         bsd_flock->l_len = (off_t)linux_flock->l_len;
1399         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1400 }
1401
1402 /*
1403  * MPSAFE
1404  */
1405 static void
1406 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1407 {
1408         switch (bsd_flock->l_type) {
1409         case F_RDLCK:
1410                 linux_flock->l_type = LINUX_F_RDLCK;
1411                 break;
1412         case F_WRLCK:
1413                 linux_flock->l_type = LINUX_F_WRLCK;
1414                 break;
1415         case F_UNLCK:
1416                 linux_flock->l_type = LINUX_F_UNLCK;
1417                 break;
1418         }
1419         linux_flock->l_whence = bsd_flock->l_whence;
1420         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1421         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1422         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1423 }
1424 #endif /* __i386__ */
1425
1426 /*
1427  * MPSAFE
1428  */
1429 static int
1430 linux_fcntl_common(struct linux_fcntl64_args *args)
1431 {
1432         struct thread *td = curthread;
1433         struct l_flock linux_flock;
1434         struct file *fp;
1435         union fcntl_dat dat;
1436         int error, cmd;
1437
1438         switch (args->cmd) {
1439         case LINUX_F_DUPFD:
1440                 cmd = F_DUPFD;
1441                 dat.fc_fd = args->arg;
1442                 break;
1443         case LINUX_F_GETFD:
1444                 cmd = F_GETFD;
1445                 break;
1446         case LINUX_F_SETFD:
1447                 cmd = F_SETFD;
1448                 dat.fc_cloexec = args->arg;
1449                 break;
1450         case LINUX_F_GETFL:
1451                 cmd = F_GETFL;
1452                 break;
1453         case LINUX_F_SETFL:
1454                 cmd = F_SETFL;
1455                 dat.fc_flags = 0;
1456                 if (args->arg & LINUX_O_NDELAY)
1457                         dat.fc_flags |= O_NONBLOCK;
1458                 if (args->arg & LINUX_O_APPEND)
1459                         dat.fc_flags |= O_APPEND;
1460                 if (args->arg & LINUX_O_SYNC)
1461                         dat.fc_flags |= O_FSYNC;
1462                 if (args->arg & LINUX_FASYNC)
1463                         dat.fc_flags |= O_ASYNC;
1464                 break;
1465         case LINUX_F_GETLK:
1466         case LINUX_F_SETLK:
1467         case LINUX_F_SETLKW:
1468                 cmd = F_GETLK;
1469                 error = copyin((caddr_t)args->arg, &linux_flock,
1470                     sizeof(linux_flock));
1471                 if (error)
1472                         return (error);
1473                 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
1474                 break;
1475         case LINUX_F_GETOWN:
1476                 cmd = F_GETOWN;
1477                 break;
1478         case LINUX_F_SETOWN:
1479                 /*
1480                  * XXX some Linux applications depend on F_SETOWN having no
1481                  * significant effect for pipes (SIGIO is not delivered for
1482                  * pipes under Linux-2.2.35 at least).
1483                  */
1484                 fp = holdfp(td->td_proc->p_fd, args->fd, -1);
1485                 if (fp == NULL)
1486                         return (EBADF);
1487                 if (fp->f_type == DTYPE_PIPE) {
1488                         fdrop(fp);
1489                         return (EINVAL);
1490                 }
1491                 fdrop(fp);
1492                 cmd = F_SETOWN;
1493                 dat.fc_owner = args->arg;
1494                 break;
1495         default:
1496                 return (EINVAL);
1497         }
1498
1499         /* MPSAFE */
1500         error = kern_fcntl(args->fd, cmd, &dat, td->td_ucred);
1501
1502         if (error == 0) {
1503                 switch (args->cmd) {
1504                 case LINUX_F_DUPFD:
1505                         args->sysmsg_iresult = dat.fc_fd;
1506                         break;
1507                 case LINUX_F_GETFD:
1508                         args->sysmsg_iresult = dat.fc_cloexec;
1509                         break;
1510                 case LINUX_F_SETFD:
1511                         break;
1512                 case LINUX_F_GETFL:
1513                         args->sysmsg_iresult = 0;
1514                         if (dat.fc_flags & O_RDONLY)
1515                                 args->sysmsg_iresult |= LINUX_O_RDONLY;
1516                         if (dat.fc_flags & O_WRONLY)
1517                                 args->sysmsg_iresult |= LINUX_O_WRONLY;
1518                         if (dat.fc_flags & O_RDWR)
1519                                 args->sysmsg_iresult |= LINUX_O_RDWR;
1520                         if (dat.fc_flags & O_NDELAY)
1521                                 args->sysmsg_iresult |= LINUX_O_NONBLOCK;
1522                         if (dat.fc_flags & O_APPEND)
1523                                 args->sysmsg_iresult |= LINUX_O_APPEND;
1524                         if (dat.fc_flags & O_FSYNC)
1525                                 args->sysmsg_iresult |= LINUX_O_SYNC;
1526                         if (dat.fc_flags & O_ASYNC)
1527                                 args->sysmsg_iresult |= LINUX_FASYNC;
1528                         break;
1529                 case LINUX_F_GETLK:
1530                         bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1531                         error = copyout(&linux_flock, (caddr_t)args->arg,
1532                             sizeof(linux_flock));
1533                         break;
1534                 case LINUX_F_SETLK:
1535                 case LINUX_F_SETLKW:
1536                         break;
1537                 case LINUX_F_GETOWN:
1538                         args->sysmsg_iresult = dat.fc_owner;
1539                         break;
1540                 case LINUX_F_SETOWN:
1541                         break;
1542                 }
1543         }
1544
1545         return(error);
1546 }
1547
1548 /*
1549  * MPSAFE
1550  */
1551 int
1552 sys_linux_fcntl(struct linux_fcntl_args *args)
1553 {
1554         struct linux_fcntl64_args args64;
1555         int error;
1556
1557 #ifdef DEBUG
1558         if (ldebug(fcntl))
1559                 kprintf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1560 #endif
1561
1562         args64.fd = args->fd;
1563         args64.cmd = args->cmd;
1564         args64.arg = args->arg;
1565         args64.sysmsg_iresult = 0;
1566         error = linux_fcntl_common(&args64);
1567         args->sysmsg_iresult = args64.sysmsg_iresult;
1568         return(error);
1569 }
1570
1571 #if defined(__i386__)
1572 /*
1573  * MPSAFE
1574  */
1575 int
1576 sys_linux_fcntl64(struct linux_fcntl64_args *args)
1577 {
1578         struct thread *td = curthread;
1579         struct l_flock64 linux_flock;
1580         union fcntl_dat dat;
1581         int error, cmd = 0;
1582
1583 #ifdef DEBUG
1584         if (ldebug(fcntl64))
1585                 kprintf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1586 #endif
1587         if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1588             args->cmd == LINUX_F_SETLKW64) {
1589                 switch (args->cmd) {
1590                 case LINUX_F_GETLK64:
1591                         cmd = F_GETLK;
1592                         break;
1593                 case LINUX_F_SETLK64:
1594                         cmd = F_SETLK;
1595                         break;
1596                 case LINUX_F_SETLKW64:
1597                         cmd = F_SETLKW;
1598                         break;
1599                 }
1600
1601                 error = copyin((caddr_t)args->arg, &linux_flock,
1602                     sizeof(linux_flock));
1603                 if (error)
1604                         return (error);
1605                 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
1606
1607                 /* MPSAFE */
1608                 error = kern_fcntl(args->fd, cmd, &dat, td->td_ucred);
1609
1610                 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1611                         bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1612                         error = copyout(&linux_flock, (caddr_t)args->arg,
1613                             sizeof(linux_flock));
1614                 }
1615         } else {
1616                 error = linux_fcntl_common(args);
1617         }
1618
1619         return (error);
1620 }
1621 #endif /* __i386__ */
1622
1623 /*
1624  * MPALMOSTSAFE
1625  */
1626 int
1627 sys_linux_chown(struct linux_chown_args *args)
1628 {
1629         struct nlookupdata nd;
1630         char *path;
1631         int error;
1632
1633         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1634         if (error)
1635                 return (error);
1636 #ifdef DEBUG
1637         if (ldebug(chown))
1638                 kprintf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1639 #endif
1640         get_mplock();
1641         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1642         if (error == 0)
1643                 error = kern_chown(&nd, args->uid, args->gid);
1644         nlookup_done(&nd);
1645         rel_mplock();
1646         linux_free_path(&path);
1647         return(error);
1648 }
1649
1650 /*
1651  * MPALMOSTSAFE
1652  */
1653 int
1654 sys_linux_lchown(struct linux_lchown_args *args)
1655 {
1656         struct nlookupdata nd;
1657         char *path;
1658         int error;
1659
1660         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1661         if (error)
1662                 return (error);
1663 #ifdef DEBUG
1664         if (ldebug(lchown))
1665                 kprintf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1666 #endif
1667         get_mplock();
1668         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
1669         if (error == 0)
1670                 error = kern_chown(&nd, args->uid, args->gid);
1671         nlookup_done(&nd);
1672         rel_mplock();
1673         linux_free_path(&path);
1674         return(error);
1675 }
1676
1677 int
1678 sys_linux_fchmodat(struct linux_fchmodat_args *args)
1679 {
1680         struct fchmodat_args uap;
1681         int error;
1682
1683         uap.fd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
1684         uap.path = args->filename;
1685         uap.mode = args->mode;
1686         uap.flags = 0;
1687
1688         error = sys_fchmodat(&uap);
1689
1690         return (error);
1691 }
1692
1693 int
1694 sys_linux_fchownat(struct linux_fchownat_args *args)
1695 {
1696         struct fchownat_args uap;
1697         int error;
1698
1699         if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
1700                 return (EINVAL);
1701
1702         uap.fd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
1703         uap.path = args->filename;
1704         uap.uid = args->uid;
1705         uap.gid = args->gid;
1706         uap.flags = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
1707             AT_SYMLINK_NOFOLLOW;
1708
1709         error = sys_fchownat(&uap);
1710
1711         return (error);
1712 }
1713
1714 int
1715 sys_linux_faccessat(struct linux_faccessat_args *args)
1716 {
1717         struct faccessat_args uap;
1718         int error;
1719
1720         uap.fd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
1721         uap.path = args->filename;
1722         uap.amode = args->mode;
1723         uap.flags = 0;
1724
1725         error = sys_faccessat(&uap);
1726
1727         return error;
1728 }