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