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