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