kernel - Move MP lock inward, plus misc other stuff
[dragonfly.git] / sys / emulation / linux / linux_file.c
1 /*-
2  * Copyright (c) 1994-1995 Søren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer 
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/compat/linux/linux_file.c,v 1.41.2.6 2003/01/06 09:19:43 fjoe Exp $
29  * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.39 2008/09/28 05:08:16 dillon Exp $
30  */
31
32 #include "opt_compat.h"
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/dirent.h>
38 #include <sys/fcntl.h>
39 #include <sys/file.h>
40 #include <sys/stat.h>
41 #include <sys/filedesc.h>
42 #include <sys/kern_syscall.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mount.h>
46 #include <sys/nlookup.h>
47 #include <sys/proc.h>
48 #include <sys/sysproto.h>
49 #include <sys/tty.h>
50 #include <sys/vnode.h>
51
52 #include <vfs/ufs/quota.h>
53 #include <vfs/ufs/ufsmount.h>
54
55 #include <sys/file2.h>
56
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         get_mplock();
79         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
80         if (error == 0) {
81                 error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC,
82                                   args->mode, &args->sysmsg_iresult);
83         }
84         rel_mplock();
85         linux_free_path(&path);
86         return(error);
87 }
88
89 /*
90  * MPALMOSTSAFE
91  */
92 int
93 sys_linux_open(struct linux_open_args *args)
94 {
95         struct thread *td = curthread;
96         struct proc *p = td->td_proc;
97         struct nlookupdata nd;
98         char *path;
99         int error, flags;
100
101         if (args->flags & LINUX_O_CREAT) {
102                 error = linux_copyin_path(args->path, &path,
103                     LINUX_PATH_CREATE);
104         } else {
105                 error = linux_copyin_path(args->path, &path,
106                     LINUX_PATH_EXISTS);
107         }
108         if (error)
109                 return (error);
110
111 #ifdef DEBUG
112         if (ldebug(open))
113                 kprintf(ARGS(open, "%s, 0x%x, 0x%x"), path, args->flags,
114                     args->mode);
115 #endif
116         flags = 0;
117         if (args->flags & LINUX_O_RDONLY)
118                 flags |= O_RDONLY;
119         if (args->flags & LINUX_O_WRONLY)
120                 flags |= O_WRONLY;
121         if (args->flags & LINUX_O_RDWR)
122                 flags |= O_RDWR;
123         if (args->flags & LINUX_O_NDELAY)
124                 flags |= O_NONBLOCK;
125         if (args->flags & LINUX_O_APPEND)
126                 flags |= O_APPEND;
127         if (args->flags & LINUX_O_SYNC)
128                 flags |= O_FSYNC;
129         if (args->flags & LINUX_O_NONBLOCK)
130                 flags |= O_NONBLOCK;
131         if (args->flags & LINUX_FASYNC)
132                 flags |= O_ASYNC;
133         if (args->flags & LINUX_O_CREAT)
134                 flags |= O_CREAT;
135         if (args->flags & LINUX_O_TRUNC)
136                 flags |= O_TRUNC;
137         if (args->flags & LINUX_O_EXCL)
138                 flags |= O_EXCL;
139         if (args->flags & LINUX_O_NOCTTY)
140                 flags |= O_NOCTTY;
141         get_mplock();
142         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
143         if (error == 0) {
144                 error = kern_open(&nd, flags,
145                                   args->mode, &args->sysmsg_iresult);
146         }
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, args->sysmsg_iresult, -1);
153                 if (fp) {
154                         if (fp->f_type == DTYPE_VNODE)
155                                 fo_ioctl(fp, TIOCSCTTY, NULL, p->p_ucred, NULL);
156                         fdrop(fp);
157                 }
158         }
159         rel_mplock();
160 #ifdef DEBUG
161         if (ldebug(open))
162                 kprintf(LMSG("open returns error %d"), error);
163 #endif
164         linux_free_path(&path);
165         return error;
166 }
167
168 /*
169  * MPSAFE
170  */
171 int
172 sys_linux_lseek(struct linux_lseek_args *args)
173 {
174         int error;
175
176 #ifdef DEBUG
177         if (ldebug(lseek))
178                 kprintf(ARGS(lseek, "%d, %ld, %d"),
179                     args->fdes, (long)args->off, args->whence);
180 #endif
181         error = kern_lseek(args->fdes, args->off, args->whence,
182                            &args->sysmsg_offset);
183
184         return error;
185 }
186
187 /*
188  * MPSAFE
189  */
190 int
191 sys_linux_llseek(struct linux_llseek_args *args)
192 {
193         int error;
194         off_t off, res;
195
196 #ifdef DEBUG
197         if (ldebug(llseek))
198                 kprintf(ARGS(llseek, "%d, %d:%d, %d"),
199                     args->fd, args->ohigh, args->olow, args->whence);
200 #endif
201         off = (args->olow) | (((off_t) args->ohigh) << 32);
202
203         error = kern_lseek(args->fd, off, args->whence, &res);
204
205         if (error == 0)
206                 error = copyout(&res, args->res, sizeof(res));
207         return (error);
208 }
209
210 /*
211  * MPSAFE
212  */
213 int
214 sys_linux_readdir(struct linux_readdir_args *args)
215 {
216         struct linux_getdents_args lda;
217         int error;
218
219         lda.fd = args->fd;
220         lda.dent = args->dent;
221         lda.count = -1;
222         lda.sysmsg_iresult = 0;
223         error = sys_linux_getdents(&lda);
224         args->sysmsg_iresult = lda.sysmsg_iresult;
225         return(error);
226 }
227
228 /*
229  * Note that linux_getdents(2) and linux_getdents64(2) have the same
230  * arguments. They only differ in the definition of struct dirent they
231  * operate on. We use this to common the code, with the exception of
232  * accessing struct dirent. Note that linux_readdir(2) is implemented
233  * by means of linux_getdents(2). In this case we never operate on
234  * struct dirent64 and thus don't need to handle it...
235  */
236
237 struct l_dirent {
238         l_long          d_ino;
239         l_off_t         d_off;
240         l_ushort        d_reclen;
241         char            d_name[LINUX_NAME_MAX + 1];
242 };
243
244 struct l_dirent64 {
245         uint64_t        d_ino;
246         int64_t         d_off;
247         l_ushort        d_reclen;
248         u_char          d_type;
249         char            d_name[LINUX_NAME_MAX + 1];
250 };
251
252 #define LINUX_RECLEN(de,namlen) \
253     ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
254
255 #define LINUX_DIRBLKSIZ         512
256
257 /*
258  * MPALMOSTSAFE
259  */
260 static int
261 getdents_common(struct linux_getdents64_args *args, int is64bit)
262 {
263         struct thread *td = curthread;
264         struct proc *p = td->td_proc;
265         struct dirent *bdp;
266         struct vnode *vp;
267         caddr_t inp, buf;               /* BSD-format */
268         int reclen;                     /* BSD-format */
269         size_t len;
270         caddr_t outp;                   /* Linux-format */
271         int linuxreclen = 0;            /* Linux-format */
272         size_t resid;
273         struct file *fp;
274         struct uio auio;
275         struct iovec aiov;
276         struct vattr va;
277         off_t off;
278         struct l_dirent linux_dirent;
279         struct l_dirent64 linux_dirent64;
280         int error, eofflag, justone;
281         size_t buflen, nbytes;
282         off_t *cookies = NULL, *cookiep;
283         int ncookies;
284
285         if ((error = holdvnode(p->p_fd, args->fd, &fp)) != 0)
286                 return (error);
287
288         get_mplock();
289         if ((fp->f_flag & FREAD) == 0) {
290                 error = EBADF;
291                 goto done;
292         }
293
294         vp = (struct vnode *) fp->f_data;
295         if (vp->v_type != VDIR) {
296                 error = EINVAL;
297                 goto done;
298         }
299
300         if ((error = VOP_GETATTR(vp, &va)) != 0)
301                 goto done;
302
303         nbytes = args->count;
304         if (nbytes == (size_t)-1) {
305                 /* readdir(2) case. Always struct dirent. */
306                 if (is64bit) {
307                         error = EINVAL;
308                         goto done;
309                 }
310                 nbytes = sizeof(linux_dirent);
311                 justone = 1;
312         } else {
313                 justone = 0;
314         }
315         if ((size_t)nbytes < 0)
316                 nbytes = 0;
317
318         off = fp->f_offset;
319
320         buflen = max(LINUX_DIRBLKSIZ, nbytes);
321         buflen = min(buflen, MAXBSIZE);
322         buf = kmalloc(buflen, M_TEMP, M_WAITOK);
323
324 again:
325         aiov.iov_base = buf;
326         aiov.iov_len = buflen;
327         auio.uio_iov = &aiov;
328         auio.uio_iovcnt = 1;
329         auio.uio_rw = UIO_READ;
330         auio.uio_segflg = UIO_SYSSPACE;
331         auio.uio_td = td;
332         auio.uio_resid = buflen;
333         auio.uio_offset = off;
334
335         if (cookies) {
336                 kfree(cookies, M_TEMP);
337                 cookies = NULL;
338         }
339
340         eofflag = 0;
341         ncookies = 0;
342         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
343                  &cookies)))
344                 goto out;
345
346         inp = buf;
347         outp = (caddr_t)args->dirent;
348         resid = nbytes;
349         if (auio.uio_resid >= buflen)
350                 goto eof;
351         len = buflen - auio.uio_resid;
352         cookiep = cookies;
353
354         if (cookies) {
355                 /*
356                  * When using cookies, the vfs has the option of reading from
357                  * a different offset than that supplied (UFS truncates the
358                  * offset to a block boundary to make sure that it never reads
359                  * partway through a directory entry, even if the directory
360                  * has been compacted).
361                  */
362                 while (len > 0 && ncookies > 0 && *cookiep < off) {
363                         bdp = (struct dirent *) inp;
364                         len -= _DIRENT_DIRSIZ(bdp);
365                         inp += _DIRENT_DIRSIZ(bdp);
366                         cookiep++;
367                         ncookies--;
368                 }
369         }
370
371         while (len > 0) {
372                 if (cookiep && ncookies == 0)
373                         break;
374                 bdp = (struct dirent *) inp;
375                 reclen = _DIRENT_DIRSIZ(bdp);
376                 if (reclen & 3) {
377                         error = EFAULT;
378                         goto out;
379                 }
380
381                 if (bdp->d_ino == 0) {
382                         inp += reclen;
383                         if (cookiep) {
384                                 off = *cookiep++;
385                                 ++off;
386                                 ncookies--;
387                         } else {
388                                 off += reclen;
389                         }
390                         len -= reclen;
391                         continue;
392                 }
393
394                 linuxreclen = (is64bit)
395                     ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
396                     : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
397
398                 if (reclen > len || resid < linuxreclen) {
399                         outp++;
400                         break;
401                 }
402
403                 bzero(&linux_dirent, sizeof(linux_dirent));
404                 bzero(&linux_dirent64, sizeof(linux_dirent64));
405                 if (justone) {
406                         /* readdir(2) case. */
407                         linux_dirent.d_ino = (l_long)INO64TO32(bdp->d_ino);
408                         linux_dirent.d_off = (l_off_t)linuxreclen;
409                         linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
410                         strcpy(linux_dirent.d_name, bdp->d_name);
411                         error = copyout(&linux_dirent, outp, linuxreclen);
412                 } else {
413                         if (is64bit) {
414                                 linux_dirent64.d_ino = bdp->d_ino;
415                                 linux_dirent64.d_off = (cookiep)
416                                     ? (l_off_t)*cookiep
417                                     : (l_off_t)(off + reclen);
418                                 linux_dirent64.d_reclen =
419                                     (l_ushort)linuxreclen;
420                                 linux_dirent64.d_type = bdp->d_type;
421                                 strcpy(linux_dirent64.d_name, bdp->d_name);
422                                 error = copyout(&linux_dirent64, outp,
423                                     linuxreclen);
424                         } else {
425                                 linux_dirent.d_ino = INO64TO32(bdp->d_ino);
426                                 linux_dirent.d_off = (cookiep)
427                                     ? (l_off_t)*cookiep
428                                     : (l_off_t)(off + reclen);
429                                 linux_dirent.d_reclen = (l_ushort)linuxreclen;
430                                 strcpy(linux_dirent.d_name, bdp->d_name);
431                                 error = copyout(&linux_dirent, outp,
432                                     linuxreclen);
433                         }
434                 }
435                 if (error)
436                         goto out;
437
438                 inp += reclen;
439                 if (cookiep) {
440                         off = *cookiep++;
441                         ++off;
442                         ncookies--;
443                 } else {
444                         off += reclen;
445                 }
446
447                 outp += linuxreclen;
448                 resid -= linuxreclen;
449                 len -= reclen;
450                 if (justone)
451                         break;
452         }
453
454         if (outp == (caddr_t)args->dirent && eofflag == 0)
455                 goto again;
456
457         fp->f_offset = off;
458         if (justone)
459                 nbytes = resid + linuxreclen;
460
461 eof:
462         args->sysmsg_iresult = (int)(nbytes - resid);
463
464 out:
465         if (cookies)
466                 kfree(cookies, M_TEMP);
467
468         kfree(buf, M_TEMP);
469 done:
470         rel_mplock();
471         fdrop(fp);
472         return (error);
473 }
474
475 /*
476  * MPSAFE
477  */
478 int
479 sys_linux_getdents(struct linux_getdents_args *args)
480 {
481 #ifdef DEBUG
482         if (ldebug(getdents))
483                 kprintf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
484 #endif
485         return (getdents_common((struct linux_getdents64_args*)args, 0));
486 }
487
488 /*
489  * MPSAFE
490  */
491 int
492 sys_linux_getdents64(struct linux_getdents64_args *args)
493 {
494 #ifdef DEBUG
495         if (ldebug(getdents64))
496                 kprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
497 #endif
498         return (getdents_common(args, 1));
499 }
500
501 /*
502  * These exist mainly for hooks for doing /compat/linux translation.
503  *
504  * MPALMOSTSAFE
505  */
506 int
507 sys_linux_access(struct linux_access_args *args)
508 {
509         struct nlookupdata nd;
510         char *path;
511         int error;
512
513         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
514         if (error)
515                 return (error);
516 #ifdef DEBUG
517         if (ldebug(access))
518                 kprintf(ARGS(access, "%s, %d"), path, args->flags);
519 #endif
520         get_mplock();
521         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
522         if (error == 0)
523                 error = kern_access(&nd, args->flags, 0);
524         nlookup_done(&nd);
525         rel_mplock();
526         linux_free_path(&path);
527         return(error);
528 }
529
530 /*
531  * MPALMOSTSAFE
532  */
533 int
534 sys_linux_unlink(struct linux_unlink_args *args)
535 {
536         struct nlookupdata nd;
537         char *path;
538         int error;
539
540         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
541         if (error)
542                 return (error);
543 #ifdef DEBUG
544         if (ldebug(unlink))
545                 kprintf(ARGS(unlink, "%s"), path);
546 #endif
547         get_mplock();
548         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
549         if (error == 0)
550                 error = kern_unlink(&nd);
551         nlookup_done(&nd);
552         rel_mplock();
553         linux_free_path(&path);
554         return(error);
555 }
556
557 /*
558  * MPALMOSTSAFE
559  */
560 int
561 sys_linux_chdir(struct linux_chdir_args *args)
562 {
563         struct nlookupdata nd;
564         char *path;
565         int error;
566
567         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
568         if (error)
569                 return (error);
570 #ifdef DEBUG
571         if (ldebug(chdir))
572                 kprintf(ARGS(chdir, "%s"), path);
573 #endif
574         get_mplock();
575         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
576         if (error == 0) {
577                 error = kern_chdir(&nd);
578                 nlookup_done(&nd);
579         }
580         rel_mplock();
581         linux_free_path(&path);
582         return(error);
583 }
584
585 /*
586  * MPALMOSTSAFE
587  */
588 int
589 sys_linux_chmod(struct linux_chmod_args *args)
590 {
591         struct nlookupdata nd;
592         char *path;
593         int error;
594
595         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
596         if (error)
597                 return (error);
598 #ifdef DEBUG
599         if (ldebug(chmod))
600                 kprintf(ARGS(chmod, "%s, %d"), path, args->mode);
601 #endif
602         get_mplock();
603         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
604         if (error == 0)
605                 error = kern_chmod(&nd, args->mode);
606         nlookup_done(&nd);
607         rel_mplock();
608         linux_free_path(&path);
609         return(error);
610 }
611
612 /*
613  * MPALMOSTSAFE
614  */
615 int
616 sys_linux_mkdir(struct linux_mkdir_args *args)
617 {
618         struct nlookupdata nd;
619         char *path;
620         int error;
621
622         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
623         if (error)
624                 return (error);
625 #ifdef DEBUG
626         if (ldebug(mkdir))
627                 kprintf(ARGS(mkdir, "%s, %d"), path, args->mode);
628 #endif
629         get_mplock();
630         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
631         if (error == 0)
632                 error = kern_mkdir(&nd, args->mode);
633         nlookup_done(&nd);
634         rel_mplock();
635
636         linux_free_path(&path);
637         return(error);
638 }
639
640 /*
641  * MPALMOSTSAFE
642  */
643 int
644 sys_linux_rmdir(struct linux_rmdir_args *args)
645 {
646         struct nlookupdata nd;
647         char *path;
648         int error;
649
650         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
651         if (error)
652                 return (error);
653 #ifdef DEBUG
654         if (ldebug(rmdir))
655                 kprintf(ARGS(rmdir, "%s"), path);
656 #endif
657         get_mplock();
658         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
659         if (error == 0)
660                 error = kern_rmdir(&nd);
661         nlookup_done(&nd);
662         rel_mplock();
663         linux_free_path(&path);
664         return(error);
665 }
666
667 /*
668  * MPALMOSTSAFE
669  */
670 int
671 sys_linux_rename(struct linux_rename_args *args)
672 {
673         struct nlookupdata fromnd, tond;
674         char *from, *to;
675         int error;
676
677         error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
678         if (error)
679                 return (error);
680         error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
681         if (error) {
682                 linux_free_path(&from);
683                 return (error);
684         }
685 #ifdef DEBUG
686         if (ldebug(rename))
687                 kprintf(ARGS(rename, "%s, %s"), from, to);
688 #endif
689         get_mplock();
690         error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0);
691         if (error == 0) {
692                 error = nlookup_init(&tond, to, UIO_SYSSPACE, 0);
693                 if (error == 0)
694                         error = kern_rename(&fromnd, &tond);
695                 nlookup_done(&tond);
696         }
697         nlookup_done(&fromnd);
698         rel_mplock();
699         linux_free_path(&from);
700         linux_free_path(&to);
701         return(error);
702 }
703
704 /*
705  * MPALMOSTSAFE
706  */
707 int
708 sys_linux_symlink(struct linux_symlink_args *args)
709 {
710         struct thread *td = curthread;
711         struct nlookupdata nd;
712         char *path, *link;
713         int error;
714         int mode;
715
716         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
717         if (error)
718                 return (error);
719         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
720         if (error) {
721                 linux_free_path(&path);
722                 return (error);
723         }
724 #ifdef DEBUG
725         if (ldebug(symlink))
726                 kprintf(ARGS(symlink, "%s, %s"), path, link);
727 #endif
728         get_mplock();
729         error = nlookup_init(&nd, link, UIO_SYSSPACE, 0);
730         if (error == 0) {
731                 mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
732                 error = kern_symlink(&nd, path, mode);
733         }
734         nlookup_done(&nd);
735         rel_mplock();
736         linux_free_path(&path);
737         linux_free_path(&link);
738         return(error);
739 }
740
741 /*
742  * MPALMOSTSAFE
743  */
744 int
745 sys_linux_readlink(struct linux_readlink_args *args)
746 {
747         struct nlookupdata nd;
748         char *path;
749         int error;
750
751         error = linux_copyin_path(args->name, &path, LINUX_PATH_EXISTS);
752         if (error)
753                 return (error);
754 #ifdef DEBUG
755         if (ldebug(readlink))
756                 kprintf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
757                     args->count);
758 #endif
759         get_mplock();
760         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
761         if (error == 0) {
762                 error = kern_readlink(&nd, args->buf, args->count,
763                                       &args->sysmsg_iresult);
764         }
765         nlookup_done(&nd);
766         rel_mplock();
767         linux_free_path(&path);
768         return(error);
769 }
770
771 /*
772  * MPALMOSTSAFE
773  */
774 int
775 sys_linux_truncate(struct linux_truncate_args *args)
776 {
777         struct nlookupdata nd;
778         char *path;
779         int error;
780
781         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
782         if (error)
783                 return (error);
784 #ifdef DEBUG
785         if (ldebug(truncate))
786                 kprintf(ARGS(truncate, "%s, %ld"), path,
787                     (long)args->length);
788 #endif
789         get_mplock();
790         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
791         if (error == 0)
792                 error = kern_truncate(&nd, args->length);
793         nlookup_done(&nd);
794         rel_mplock();
795         linux_free_path(&path);
796         return(error);
797 }
798
799 /*
800  * MPALMOSTSAFE
801  */
802 int
803 sys_linux_truncate64(struct linux_truncate64_args *args)
804 {
805         struct nlookupdata nd;
806         char *path;
807         int error;
808
809         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
810         if (error)
811                 return (error);
812 #ifdef DEBUG
813         if (ldebug(truncate64))
814                 kprintf(ARGS(truncate64, "%s, %lld"), path,
815                     (off_t)args->length);
816 #endif
817         get_mplock();
818         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
819         if (error == 0)
820                 error = kern_truncate(&nd, args->length);
821         nlookup_done(&nd);
822         rel_mplock();
823         linux_free_path(&path);
824         return error;
825 }
826
827 /*
828  * MPALMOSTSAFE
829  */
830 int
831 sys_linux_ftruncate(struct linux_ftruncate_args *args)
832 {
833         int error;
834
835 #ifdef DEBUG
836         if (ldebug(ftruncate))
837                 kprintf(ARGS(ftruncate, "%d, %ld"), args->fd,
838                     (long)args->length);
839 #endif
840         get_mplock();
841         error = kern_ftruncate(args->fd, args->length);
842         rel_mplock();
843
844         return error;
845 }
846
847 /*
848  * MPALMOSTSAFE
849  */
850 int
851 sys_linux_ftruncate64(struct linux_ftruncate64_args *args)
852 {
853         int error;
854
855 #ifdef DEBUG
856         if (ldebug(ftruncate))
857                 kprintf(ARGS(ftruncate64, "%d, %lld"), args->fd,
858                     (off_t)args->length);
859 #endif
860         get_mplock();
861         error = kern_ftruncate(args->fd, args->length);
862         rel_mplock();
863
864         return error;
865 }
866
867 /*
868  * MPALMOSTSAFE
869  */
870 int
871 sys_linux_link(struct linux_link_args *args)
872 {
873         struct nlookupdata nd, linknd;
874         char *path, *link;
875         int error;
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(link))
887                 kprintf(ARGS(link, "%s, %s"), path, link);
888 #endif
889         get_mplock();
890         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
891         if (error == 0) {
892                 error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0);
893                 if (error == 0)
894                         error = kern_link(&nd, &linknd);
895                 nlookup_done(&linknd);
896         }
897         nlookup_done(&nd);
898         rel_mplock();
899         linux_free_path(&path);
900         linux_free_path(&link);
901         return(error);
902 }
903
904 /*
905  * MPSAFE
906  */
907 int
908 sys_linux_fdatasync(struct linux_fdatasync_args *uap)
909 {
910         struct fsync_args bsd;
911         int error;
912
913         bsd.fd = uap->fd;
914         bsd.sysmsg_iresult = 0;
915
916         error = sys_fsync(&bsd);
917         uap->sysmsg_iresult = bsd.sysmsg_iresult;
918         return(error);
919 }
920
921 /*
922  * MPSAFE
923  */
924 int
925 sys_linux_pread(struct linux_pread_args *uap)
926 {
927         struct thread *td = curthread;
928         struct uio auio;
929         struct iovec aiov;
930         int error;
931
932         aiov.iov_base = uap->buf;
933         aiov.iov_len = uap->nbyte;
934         auio.uio_iov = &aiov;
935         auio.uio_iovcnt = 1;
936         auio.uio_offset = uap->offset;
937         auio.uio_resid = uap->nbyte;
938         auio.uio_rw = UIO_READ;
939         auio.uio_segflg = UIO_USERSPACE;
940         auio.uio_td = td;
941
942         if ((ssize_t)auio.uio_resid < 0) {
943                 error = EINVAL;
944         } else {
945                 error = kern_preadv(uap->fd, &auio, O_FOFFSET,
946                                     &uap->sysmsg_szresult);
947         }
948         return(error);
949 }
950
951 /*
952  * MPSAFE
953  */
954 int
955 sys_linux_pwrite(struct linux_pwrite_args *uap)
956 {
957         struct thread *td = curthread;
958         struct uio auio;
959         struct iovec aiov;
960         int error;
961
962         aiov.iov_base = uap->buf;
963         aiov.iov_len = uap->nbyte;
964         auio.uio_iov = &aiov;
965         auio.uio_iovcnt = 1;
966         auio.uio_offset = uap->offset;
967         auio.uio_resid = uap->nbyte;
968         auio.uio_rw = UIO_WRITE;
969         auio.uio_segflg = UIO_USERSPACE;
970         auio.uio_td = td;
971
972         if ((ssize_t)auio.uio_resid < 0) {
973                 error = EINVAL;
974         } else {
975                 error = kern_pwritev(uap->fd, &auio, O_FOFFSET,
976                                      &uap->sysmsg_szresult);
977         }
978         return(error);
979 }
980
981 /*
982  * MPSAFE
983  */
984 int
985 sys_linux_oldumount(struct linux_oldumount_args *args)
986 {
987         struct linux_umount_args args2;
988         int error;
989
990         args2.path = args->path;
991         args2.flags = 0;
992         args2.sysmsg_iresult = 0;
993         error = sys_linux_umount(&args2);
994         args->sysmsg_iresult = args2.sysmsg_iresult;
995         return(error);
996 }
997
998 /*
999  * MPSAFE
1000  */
1001 int
1002 sys_linux_umount(struct linux_umount_args *args)
1003 {
1004         struct unmount_args bsd;
1005         int error;
1006
1007         bsd.path = args->path;
1008         bsd.flags = args->flags;        /* XXX correct? */
1009         bsd.sysmsg_iresult = 0;
1010
1011         error = sys_unmount(&bsd);
1012         args->sysmsg_iresult = bsd.sysmsg_iresult;
1013         return(error);
1014 }
1015
1016 /*
1017  * fcntl family of syscalls
1018  */
1019 struct l_flock {
1020         l_short         l_type;
1021         l_short         l_whence;
1022         l_off_t         l_start;
1023         l_off_t         l_len;
1024         l_pid_t         l_pid;
1025 };
1026
1027 /*
1028  * MPSAFE
1029  */
1030 static void
1031 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1032 {
1033         switch (linux_flock->l_type) {
1034         case LINUX_F_RDLCK:
1035                 bsd_flock->l_type = F_RDLCK;
1036                 break;
1037         case LINUX_F_WRLCK:
1038                 bsd_flock->l_type = F_WRLCK;
1039                 break;
1040         case LINUX_F_UNLCK:
1041                 bsd_flock->l_type = F_UNLCK;
1042                 break;
1043         default:
1044                 bsd_flock->l_type = -1;
1045                 break;
1046         }
1047         bsd_flock->l_whence = linux_flock->l_whence;
1048         bsd_flock->l_start = (off_t)linux_flock->l_start;
1049         bsd_flock->l_len = (off_t)linux_flock->l_len;
1050         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1051 }
1052
1053 /*
1054  * MPSAFE
1055  */
1056 static void
1057 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1058 {
1059         switch (bsd_flock->l_type) {
1060         case F_RDLCK:
1061                 linux_flock->l_type = LINUX_F_RDLCK;
1062                 break;
1063         case F_WRLCK:
1064                 linux_flock->l_type = LINUX_F_WRLCK;
1065                 break;
1066         case F_UNLCK:
1067                 linux_flock->l_type = LINUX_F_UNLCK;
1068                 break;
1069         }
1070         linux_flock->l_whence = bsd_flock->l_whence;
1071         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1072         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1073         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1074 }
1075
1076 #if defined(__i386__)
1077 struct l_flock64 {
1078         l_short         l_type;
1079         l_short         l_whence;
1080         l_loff_t        l_start;
1081         l_loff_t        l_len;
1082         l_pid_t         l_pid;
1083 };
1084
1085 /*
1086  * MPSAFE
1087  */
1088 static void
1089 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1090 {
1091         switch (linux_flock->l_type) {
1092         case LINUX_F_RDLCK:
1093                 bsd_flock->l_type = F_RDLCK;
1094                 break;
1095         case LINUX_F_WRLCK:
1096                 bsd_flock->l_type = F_WRLCK;
1097                 break;
1098         case LINUX_F_UNLCK:
1099                 bsd_flock->l_type = F_UNLCK;
1100                 break;
1101         default:
1102                 bsd_flock->l_type = -1;
1103                 break;
1104         }
1105         bsd_flock->l_whence = linux_flock->l_whence;
1106         bsd_flock->l_start = (off_t)linux_flock->l_start;
1107         bsd_flock->l_len = (off_t)linux_flock->l_len;
1108         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1109 }
1110
1111 /*
1112  * MPSAFE
1113  */
1114 static void
1115 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1116 {
1117         switch (bsd_flock->l_type) {
1118         case F_RDLCK:
1119                 linux_flock->l_type = LINUX_F_RDLCK;
1120                 break;
1121         case F_WRLCK:
1122                 linux_flock->l_type = LINUX_F_WRLCK;
1123                 break;
1124         case F_UNLCK:
1125                 linux_flock->l_type = LINUX_F_UNLCK;
1126                 break;
1127         }
1128         linux_flock->l_whence = bsd_flock->l_whence;
1129         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1130         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1131         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1132 }
1133 #endif /* __i386__ */
1134
1135 /*
1136  * MPSAFE
1137  */
1138 static int
1139 linux_fcntl_common(struct linux_fcntl64_args *args)
1140 {
1141         struct proc *p = curproc;
1142         struct l_flock linux_flock;
1143         struct file *fp;
1144         union fcntl_dat dat;
1145         int error, cmd;
1146
1147         switch (args->cmd) {
1148         case LINUX_F_DUPFD:
1149                 cmd = F_DUPFD;
1150                 dat.fc_fd = args->arg;
1151                 break;
1152         case LINUX_F_GETFD:
1153                 cmd = F_GETFD;
1154                 break;
1155         case LINUX_F_SETFD:
1156                 cmd = F_SETFD;
1157                 dat.fc_cloexec = args->arg;
1158                 break;
1159         case LINUX_F_GETFL:
1160                 cmd = F_GETFL;
1161                 break;
1162         case LINUX_F_SETFL:
1163                 cmd = F_SETFL;
1164                 dat.fc_flags = 0;
1165                 if (args->arg & LINUX_O_NDELAY)
1166                         dat.fc_flags |= O_NONBLOCK;
1167                 if (args->arg & LINUX_O_APPEND)
1168                         dat.fc_flags |= O_APPEND;
1169                 if (args->arg & LINUX_O_SYNC)
1170                         dat.fc_flags |= O_FSYNC;
1171                 if (args->arg & LINUX_FASYNC)
1172                         dat.fc_flags |= O_ASYNC;
1173                 break;
1174         case LINUX_F_GETLK:
1175         case LINUX_F_SETLK:
1176         case LINUX_F_SETLKW:
1177                 cmd = F_GETLK;
1178                 error = copyin((caddr_t)args->arg, &linux_flock,
1179                     sizeof(linux_flock));
1180                 if (error)
1181                         return (error);
1182                 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
1183                 break;
1184         case LINUX_F_GETOWN:
1185                 cmd = F_GETOWN;
1186                 break;
1187         case LINUX_F_SETOWN:
1188                 /*
1189                  * XXX some Linux applications depend on F_SETOWN having no
1190                  * significant effect for pipes (SIGIO is not delivered for
1191                  * pipes under Linux-2.2.35 at least).
1192                  */
1193                 fp = holdfp(p->p_fd, args->fd, -1);
1194                 if (fp == NULL)
1195                         return (EBADF);
1196                 if (fp->f_type == DTYPE_PIPE) {
1197                         fdrop(fp);
1198                         return (EINVAL);
1199                 }
1200                 fdrop(fp);
1201                 cmd = F_SETOWN;
1202                 dat.fc_owner = args->arg;
1203                 break;
1204         default:
1205                 return (EINVAL);
1206         }
1207
1208         /* MPSAFE */
1209         error = kern_fcntl(args->fd, cmd, &dat, p->p_ucred);
1210
1211         if (error == 0) {
1212                 switch (args->cmd) {
1213                 case LINUX_F_DUPFD:
1214                         args->sysmsg_iresult = dat.fc_fd;
1215                         break;
1216                 case LINUX_F_GETFD:
1217                         args->sysmsg_iresult = dat.fc_cloexec;
1218                         break;
1219                 case LINUX_F_SETFD:
1220                         break;
1221                 case LINUX_F_GETFL:
1222                         args->sysmsg_iresult = 0;
1223                         if (dat.fc_flags & O_RDONLY)
1224                                 args->sysmsg_iresult |= LINUX_O_RDONLY;
1225                         if (dat.fc_flags & O_WRONLY)
1226                                 args->sysmsg_iresult |= LINUX_O_WRONLY;
1227                         if (dat.fc_flags & O_RDWR)
1228                                 args->sysmsg_iresult |= LINUX_O_RDWR;
1229                         if (dat.fc_flags & O_NDELAY)
1230                                 args->sysmsg_iresult |= LINUX_O_NONBLOCK;
1231                         if (dat.fc_flags & O_APPEND)
1232                                 args->sysmsg_iresult |= LINUX_O_APPEND;
1233                         if (dat.fc_flags & O_FSYNC)
1234                                 args->sysmsg_iresult |= LINUX_O_SYNC;
1235                         if (dat.fc_flags & O_ASYNC)
1236                                 args->sysmsg_iresult |= LINUX_FASYNC;
1237                         break;
1238                 case LINUX_F_GETLK:
1239                         bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1240                         error = copyout(&linux_flock, (caddr_t)args->arg,
1241                             sizeof(linux_flock));
1242                         break;
1243                 case LINUX_F_SETLK:
1244                 case LINUX_F_SETLKW:
1245                         break;
1246                 case LINUX_F_GETOWN:
1247                         args->sysmsg_iresult = dat.fc_owner;
1248                         break;
1249                 case LINUX_F_SETOWN:
1250                         break;
1251                 }
1252         }
1253
1254         return(error);
1255 }
1256
1257 /*
1258  * MPSAFE
1259  */
1260 int
1261 sys_linux_fcntl(struct linux_fcntl_args *args)
1262 {
1263         struct linux_fcntl64_args args64;
1264         int error;
1265
1266 #ifdef DEBUG
1267         if (ldebug(fcntl))
1268                 kprintf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1269 #endif
1270
1271         args64.fd = args->fd;
1272         args64.cmd = args->cmd;
1273         args64.arg = args->arg;
1274         args64.sysmsg_iresult = 0;
1275         error = linux_fcntl_common(&args64);
1276         args->sysmsg_iresult = args64.sysmsg_iresult;
1277         return(error);
1278 }
1279
1280 #if defined(__i386__)
1281 /*
1282  * MPSAFE
1283  */
1284 int
1285 sys_linux_fcntl64(struct linux_fcntl64_args *args)
1286 {
1287         struct l_flock64 linux_flock;
1288         union fcntl_dat dat;
1289         int error, cmd = 0;
1290
1291 #ifdef DEBUG
1292         if (ldebug(fcntl64))
1293                 kprintf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1294 #endif
1295         if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1296             args->cmd == LINUX_F_SETLKW64) {
1297                 switch (args->cmd) {
1298                 case LINUX_F_GETLK64:
1299                         cmd = F_GETLK;
1300                         break;
1301                 case LINUX_F_SETLK64:
1302                         cmd = F_SETLK;
1303                         break;
1304                 case LINUX_F_SETLKW64:
1305                         cmd = F_SETLKW;
1306                         break;
1307                 }
1308
1309                 error = copyin((caddr_t)args->arg, &linux_flock,
1310                     sizeof(linux_flock));
1311                 if (error)
1312                         return (error);
1313                 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
1314
1315                 /* MPSAFE */
1316                 error = kern_fcntl(args->fd, cmd, &dat, curproc->p_ucred);
1317
1318                 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1319                         bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1320                         error = copyout(&linux_flock, (caddr_t)args->arg,
1321                             sizeof(linux_flock));
1322                 }
1323         } else {
1324                 error = linux_fcntl_common(args);
1325         }
1326
1327         return (error);
1328 }
1329 #endif /* __i386__ */
1330
1331 /*
1332  * MPALMOSTSAFE
1333  */
1334 int
1335 sys_linux_chown(struct linux_chown_args *args)
1336 {
1337         struct nlookupdata nd;
1338         char *path;
1339         int error;
1340
1341         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1342         if (error)
1343                 return (error);
1344 #ifdef DEBUG
1345         if (ldebug(chown))
1346                 kprintf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1347 #endif
1348         get_mplock();
1349         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1350         if (error == 0)
1351                 error = kern_chown(&nd, args->uid, args->gid);
1352         nlookup_done(&nd);
1353         rel_mplock();
1354         linux_free_path(&path);
1355         return(error);
1356 }
1357
1358 /*
1359  * MPALMOSTSAFE
1360  */
1361 int
1362 sys_linux_lchown(struct linux_lchown_args *args)
1363 {
1364         struct nlookupdata nd;
1365         char *path;
1366         int error;
1367
1368         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1369         if (error)
1370                 return (error);
1371 #ifdef DEBUG
1372         if (ldebug(lchown))
1373                 kprintf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1374 #endif
1375         get_mplock();
1376         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
1377         if (error == 0)
1378                 error = kern_chown(&nd, args->uid, args->gid);
1379         nlookup_done(&nd);
1380         rel_mplock();
1381         linux_free_path(&path);
1382         return(error);
1383 }
1384