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