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