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