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