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