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