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