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