Split mkfifo().
[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.14 2003/11/13 04:04:42 daver 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, 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, 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"), args->from, args->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"), args->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_ftruncate(struct linux_ftruncate_args *args)
718 {
719         int error;
720
721 #ifdef DEBUG
722         if (ldebug(ftruncate))
723                 printf(ARGS(ftruncate, "%d, %ld"), args->fd,
724                     (long)args->length);
725 #endif
726         error = kern_ftruncate(args->fd, args->length);
727
728         return error;
729 }
730
731 int
732 linux_link(struct linux_link_args *args)
733 {
734         struct thread *td = curthread;
735         struct nameidata nd, linknd;
736         char *path, *link;
737         int error;
738
739         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
740         if (error)
741                 return (error);
742         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
743         if (error) {
744                 linux_free_path(&path);
745                 return (error);
746         }
747 #ifdef DEBUG
748         if (ldebug(link))
749                 printf(ARGS(link, "%s, %s"), path, link);
750 #endif
751         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW | CNP_NOOBJ, UIO_SYSSPACE,
752             path, td);
753         NDINIT(&linknd, NAMEI_CREATE, CNP_LOCKPARENT | CNP_NOOBJ,
754             UIO_SYSSPACE, link, td);
755
756         error = kern_link(&nd, &linknd);
757
758         linux_free_path(&path);
759         linux_free_path(&link);
760         return(error);
761 }
762
763 #ifndef __alpha__
764 int
765 linux_fdatasync(struct linux_fdatasync_args *uap)
766 {
767         struct fsync_args bsd;
768         int error;
769
770         bsd.fd = uap->fd;
771         bsd.sysmsg_result = 0;
772
773         error = fsync(&bsd);
774         uap->sysmsg_result = bsd.sysmsg_result;
775         return(error);
776 }
777 #endif /*!__alpha__*/
778
779 int
780 linux_pread(struct linux_pread_args *uap)
781 {
782         struct thread *td = curthread;
783         struct uio auio;
784         struct iovec aiov;
785         int error;
786
787         aiov.iov_base = uap->buf;
788         aiov.iov_len = uap->nbyte;
789         auio.uio_iov = &aiov;
790         auio.uio_iovcnt = 1;
791         auio.uio_offset = uap->offset;
792         auio.uio_resid = uap->nbyte;
793         auio.uio_rw = UIO_READ;
794         auio.uio_segflg = UIO_USERSPACE;
795         auio.uio_td = td;
796
797         error = kern_readv(uap->fd, &auio, FOF_OFFSET, &uap->sysmsg_result);
798
799         return(error);
800 }
801
802 int
803 linux_pwrite(struct linux_pwrite_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_WRITE;
817         auio.uio_segflg = UIO_USERSPACE;
818         auio.uio_td = td;
819
820         error = kern_writev(uap->fd, &auio, FOF_OFFSET, &uap->sysmsg_result);
821
822         return(error);
823 }
824
825 int
826 linux_oldumount(struct linux_oldumount_args *args)
827 {
828         struct linux_umount_args args2;
829         int error;
830
831         args2.path = args->path;
832         args2.flags = 0;
833         args2.sysmsg_result = 0;
834         error = linux_umount(&args2);
835         args->sysmsg_result = args2.sysmsg_result;
836         return(error);
837 }
838
839 int
840 linux_umount(struct linux_umount_args *args)
841 {
842         struct unmount_args bsd;
843         int error;
844
845         bsd.path = args->path;
846         bsd.flags = args->flags;        /* XXX correct? */
847         bsd.sysmsg_result = 0;
848
849         error = unmount(&bsd);
850         args->sysmsg_result = bsd.sysmsg_result;
851         return(error);
852 }
853
854 /*
855  * fcntl family of syscalls
856  */
857
858 struct l_flock {
859         l_short         l_type;
860         l_short         l_whence;
861         l_off_t         l_start;
862         l_off_t         l_len;
863         l_pid_t         l_pid;
864 };
865
866 static void
867 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
868 {
869         switch (linux_flock->l_type) {
870         case LINUX_F_RDLCK:
871                 bsd_flock->l_type = F_RDLCK;
872                 break;
873         case LINUX_F_WRLCK:
874                 bsd_flock->l_type = F_WRLCK;
875                 break;
876         case LINUX_F_UNLCK:
877                 bsd_flock->l_type = F_UNLCK;
878                 break;
879         default:
880                 bsd_flock->l_type = -1;
881                 break;
882         }
883         bsd_flock->l_whence = linux_flock->l_whence;
884         bsd_flock->l_start = (off_t)linux_flock->l_start;
885         bsd_flock->l_len = (off_t)linux_flock->l_len;
886         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
887 }
888
889 static void
890 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
891 {
892         switch (bsd_flock->l_type) {
893         case F_RDLCK:
894                 linux_flock->l_type = LINUX_F_RDLCK;
895                 break;
896         case F_WRLCK:
897                 linux_flock->l_type = LINUX_F_WRLCK;
898                 break;
899         case F_UNLCK:
900                 linux_flock->l_type = LINUX_F_UNLCK;
901                 break;
902         }
903         linux_flock->l_whence = bsd_flock->l_whence;
904         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
905         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
906         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
907 }
908
909 #if defined(__i386__)
910 struct l_flock64 {
911         l_short         l_type;
912         l_short         l_whence;
913         l_loff_t        l_start;
914         l_loff_t        l_len;
915         l_pid_t         l_pid;
916 };
917
918 static void
919 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
920 {
921         switch (linux_flock->l_type) {
922         case LINUX_F_RDLCK:
923                 bsd_flock->l_type = F_RDLCK;
924                 break;
925         case LINUX_F_WRLCK:
926                 bsd_flock->l_type = F_WRLCK;
927                 break;
928         case LINUX_F_UNLCK:
929                 bsd_flock->l_type = F_UNLCK;
930                 break;
931         default:
932                 bsd_flock->l_type = -1;
933                 break;
934         }
935         bsd_flock->l_whence = linux_flock->l_whence;
936         bsd_flock->l_start = (off_t)linux_flock->l_start;
937         bsd_flock->l_len = (off_t)linux_flock->l_len;
938         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
939 }
940
941 static void
942 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
943 {
944         switch (bsd_flock->l_type) {
945         case F_RDLCK:
946                 linux_flock->l_type = LINUX_F_RDLCK;
947                 break;
948         case F_WRLCK:
949                 linux_flock->l_type = LINUX_F_WRLCK;
950                 break;
951         case F_UNLCK:
952                 linux_flock->l_type = LINUX_F_UNLCK;
953                 break;
954         }
955         linux_flock->l_whence = bsd_flock->l_whence;
956         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
957         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
958         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
959 }
960 #endif /* __i386__ */
961
962 #if defined(__alpha__)
963 #define linux_fcntl64_args      linux_fcntl_args
964 #endif
965
966 static int
967 linux_fcntl_common(struct linux_fcntl64_args *args)
968 {
969         struct proc *p = curproc;
970         struct l_flock linux_flock;
971         struct filedesc *fdp;
972         struct file *fp;
973         union fcntl_dat dat;
974         int error, cmd;
975
976         switch (args->cmd) {
977         case LINUX_F_DUPFD:
978                 cmd = F_DUPFD;
979                 dat.fc_fd = args->arg;
980                 break;
981         case LINUX_F_GETFD:
982                 cmd = F_GETFD;
983                 break;
984         case LINUX_F_SETFD:
985                 cmd = F_SETFD;
986                 dat.fc_cloexec = args->arg;
987                 break;
988         case LINUX_F_GETFL:
989                 cmd = F_GETFL;
990                 break;
991         case LINUX_F_SETFL:
992                 cmd = F_SETFL;
993                 dat.fc_flags = 0;
994                 if (args->arg & LINUX_O_NDELAY)
995                         dat.fc_flags |= O_NONBLOCK;
996                 if (args->arg & LINUX_O_APPEND)
997                         dat.fc_flags |= O_APPEND;
998                 if (args->arg & LINUX_O_SYNC)
999                         dat.fc_flags |= O_FSYNC;
1000                 if (args->arg & LINUX_FASYNC)
1001                         dat.fc_flags |= O_ASYNC;
1002                 break;
1003         case LINUX_F_GETLK:
1004         case LINUX_F_SETLK:
1005         case LINUX_F_SETLKW:
1006                 cmd = F_GETLK;
1007                 error = copyin((caddr_t)args->arg, &linux_flock,
1008                     sizeof(linux_flock));
1009                 if (error)
1010                         return (error);
1011                 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
1012                 break;
1013         case LINUX_F_GETOWN:
1014                 cmd = F_GETOWN;
1015                 break;
1016         case LINUX_F_SETOWN:
1017                 /*
1018                  * XXX some Linux applications depend on F_SETOWN having no
1019                  * significant effect for pipes (SIGIO is not delivered for
1020                  * pipes under Linux-2.2.35 at least).
1021                  */
1022                 fdp = p->p_fd;
1023                 if ((u_int)args->fd >= fdp->fd_nfiles ||
1024                     (fp = fdp->fd_ofiles[args->fd]) == NULL)
1025                         return (EBADF);
1026                 if (fp->f_type == DTYPE_PIPE)
1027                         return (EINVAL);
1028                 cmd = F_SETOWN;
1029                 dat.fc_owner = args->arg;
1030                 break;
1031         default:
1032                 return (EINVAL);
1033         }
1034
1035         error = kern_fcntl(args->fd, cmd, &dat);
1036
1037         if (error == 0) {
1038                 switch (args->cmd) {
1039                 case LINUX_F_DUPFD:
1040                         args->sysmsg_result = dat.fc_fd;
1041                         break;
1042                 case LINUX_F_GETFD:
1043                         args->sysmsg_result = dat.fc_cloexec;
1044                         break;
1045                 case LINUX_F_SETFD:
1046                         break;
1047                 case LINUX_F_GETFL:
1048                         args->sysmsg_result = 0;
1049                         if (dat.fc_flags & O_RDONLY)
1050                                 args->sysmsg_result |= LINUX_O_RDONLY;
1051                         if (dat.fc_flags & O_WRONLY)
1052                                 args->sysmsg_result |= LINUX_O_WRONLY;
1053                         if (dat.fc_flags & O_RDWR)
1054                                 args->sysmsg_result |= LINUX_O_RDWR;
1055                         if (dat.fc_flags & O_NDELAY)
1056                                 args->sysmsg_result |= LINUX_O_NONBLOCK;
1057                         if (dat.fc_flags & O_APPEND)
1058                                 args->sysmsg_result |= LINUX_O_APPEND;
1059                         if (dat.fc_flags & O_FSYNC)
1060                                 args->sysmsg_result |= LINUX_O_SYNC;
1061                         if (dat.fc_flags & O_ASYNC)
1062                                 args->sysmsg_result |= LINUX_FASYNC;
1063                         break;
1064                 case LINUX_F_GETLK:
1065                         bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1066                         error = copyout(&linux_flock, (caddr_t)args->arg,
1067                             sizeof(linux_flock));
1068                         break;
1069                 case LINUX_F_SETLK:
1070                 case LINUX_F_SETLKW:
1071                         break;
1072                 case LINUX_F_GETOWN:
1073                         args->sysmsg_result = dat.fc_owner;
1074                         break;
1075                 case LINUX_F_SETOWN:
1076                         break;
1077                 }
1078         }
1079
1080         return(error);
1081 }
1082
1083 int
1084 linux_fcntl(struct linux_fcntl_args *args)
1085 {
1086         struct linux_fcntl64_args args64;
1087         int error;
1088
1089 #ifdef DEBUG
1090         if (ldebug(fcntl))
1091                 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1092 #endif
1093
1094         args64.fd = args->fd;
1095         args64.cmd = args->cmd;
1096         args64.arg = args->arg;
1097         args64.sysmsg_result = 0;
1098         error = linux_fcntl_common(&args64);
1099         args->sysmsg_result = args64.sysmsg_result;
1100         return(error);
1101 }
1102
1103 #if defined(__i386__)
1104 int
1105 linux_fcntl64(struct linux_fcntl64_args *args)
1106 {
1107         struct l_flock64 linux_flock;
1108         union fcntl_dat dat;
1109         int error, cmd = 0;
1110
1111 #ifdef DEBUG
1112         if (ldebug(fcntl64))
1113                 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1114 #endif
1115         if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1116             args->cmd == LINUX_F_SETLKW64) {
1117                 switch (args->cmd) {
1118                 case LINUX_F_GETLK64:
1119                         cmd = F_GETLK;
1120                         break;
1121                 case LINUX_F_SETLK64:
1122                         cmd = F_SETLK;
1123                         break;
1124                 case LINUX_F_SETLKW64:
1125                         cmd = F_SETLKW;
1126                         break;
1127                 }
1128
1129                 error = copyin((caddr_t)args->arg, &linux_flock,
1130                     sizeof(linux_flock));
1131                 if (error)
1132                         return (error);
1133                 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
1134
1135                 error = kern_fcntl(args->fd, cmd, &dat);
1136
1137                 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1138                         bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1139                         error = copyout(&linux_flock, (caddr_t)args->arg,
1140                             sizeof(linux_flock));
1141                 }
1142         } else {
1143                 error = linux_fcntl_common(args);
1144         }
1145
1146         return (error);
1147 }
1148 #endif /* __i386__ */
1149
1150 int
1151 linux_chown(struct linux_chown_args *args)
1152 {
1153         struct thread *td = curthread;
1154         struct nameidata nd;
1155         char *path;
1156         int error;
1157
1158         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1159         if (error)
1160                 return (error);
1161 #ifdef DEBUG
1162         if (ldebug(chown))
1163                 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1164 #endif
1165         NDINIT(&nd, NAMEI_LOOKUP, CNP_FOLLOW, UIO_SYSSPACE, path, td);
1166
1167         error = kern_chown(&nd, args->uid, args->gid);
1168
1169         linux_free_path(&path);
1170         return(error);
1171 }
1172
1173 int
1174 linux_lchown(struct linux_lchown_args *args)
1175 {
1176         struct thread *td = curthread;
1177         struct nameidata 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(lchown))
1186                 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1187 #endif
1188         NDINIT(&nd, NAMEI_LOOKUP, 0, UIO_SYSSPACE, path, td);
1189
1190         error = kern_chown(&nd, args->uid, args->gid);
1191
1192         linux_free_path(&path);
1193         return(error);
1194 }
1195