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