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